/* SPDX-License-Identifier: GPL-2.0-or-later */
/* Copyright(c) 2020 - 2023 Allwinner Technology Co.,Ltd. All rights reserved. */
/*
 * linux-4.9/drivers/media/platform/sunxi-vfe/vfe.c
 *
 * Copyright (c) 2007-2017 Allwinnertech Co., Ltd.
 *
 * This software is licensed under the terms of the GNU General Public
 * License version 2, as published by the Free Software Foundation, and
 * may be copied, distributed, and modified under those terms.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */

/*
 * sunxi Camera Interface  driver
 * Author: raymonxiu
 */
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/version.h>
#include <linux/mutex.h>
#include <linux/videodev2.h>
#include <linux/delay.h>
#include <linux/string.h>

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
#include <linux/freezer.h>
#endif

#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/moduleparam.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-common.h>
#include <media/v4l2-mediabus.h>
#include <media/v4l2-subdev.h>
#include <media/videobuf2-dma-contig.h>

#include <linux/regulator/consumer.h>
#ifdef CONFIG_DEVFREQ_DRAM_FREQ_WITH_SOFT_NOTIFY
#include <linux/sunxi_dramfreq.h>
#endif

#include "vfe.h"

#include "bsp_common.h"
#include "lib/bsp_isp_algo.h"
#include "csi_cci/bsp_cci.h"
#include "csi_cci/cci_helper.h"
#include "config.h"
#include "device/camera_cfg.h"
#include "device/sensor_helper.h"
#include "utility/sensor_info.h"
#include "utility/vfe_io.h"
#include "csi/sunxi_csi.h"
#include "sunxi_isp.h"
#include "mipi_csi/sunxi_mipi.h"

#define IS_FLAG(x, y) (((x)&(y)) == y)
#define CLIP_MAX(x, max) ((x) > max ? max : x)

#define VFE_MAJOR_VERSION 1
#define VFE_MINOR_VERSION 0
#define VFE_RELEASE       0
#define VFE_VERSION \
  KERNEL_VERSION(VFE_MAJOR_VERSION, VFE_MINOR_VERSION, VFE_RELEASE)
#define VFE_MODULE_NAME "sunxi_vfe"
#define VID_N_OFF      8

#define MCLK_OUT_RATE   (24*1000*1000)
#define MAX_FRAME_MEM   (150*1024*1024)
#define MIN_WIDTH       (32)
#define MIN_HEIGHT      (32)
#define MAX_WIDTH       (4800)
#define MAX_HEIGHT      (4800)
#define DUMP_CSI       (1 << 0)
#define DUMP_ISP      (1 << 1)

/* #define _REGULATOR_CHANGE_ */

struct vfe_dev *vfe_dev_gbl[2];

static char ccm[I2C_NAME_SIZE] = "";
static uint i2c_addr = 0xff;

static char act_name[I2C_NAME_SIZE] = "";
static uint act_slave = 0xff;
static uint define_sensor_list = 0xff;
static uint vfe_i2c_dbg;
static uint isp_log;
static uint vips = 0xffff;

static int touch_flash_flag;
static int ev_cumul;

unsigned int isp_reparse_flag;

static unsigned int frame_cnt;
static unsigned int vfe_dump;
struct mutex probe_hdl_lock;
struct file *fp_dbg;
static char LogFileName[128] = "/system/etc/hawkview/log.bin";

module_param_string(ccm, ccm, sizeof(ccm), S_IRUGO | S_IWUSR);
module_param(i2c_addr, uint, S_IRUGO | S_IWUSR);

module_param_string(act_name, act_name, sizeof(act_name), S_IRUGO | S_IWUSR);
module_param(act_slave, uint, S_IRUGO | S_IWUSR);
module_param(define_sensor_list, uint, S_IRUGO | S_IWUSR);
module_param(vfe_i2c_dbg, uint, S_IRUGO | S_IWUSR);
module_param(isp_log, uint, S_IRUGO | S_IWUSR);
module_param(vips, uint, S_IRUGO | S_IWUSR);

static ssize_t vfe_dbg_en_show(struct device *dev,
		    struct device_attribute *attr, char *buf)
{
	return sprintf(buf, "%u\n", vfe_dbg_en);
}

static ssize_t vfe_dbg_en_store(struct device *dev,
		    struct device_attribute *attr,
		    const char *buf, size_t count)
{
	int err;
	unsigned long val;

	err = kstrtoul(buf, 10, &val);
	if (err) {
		vfe_print("Invalid size\n");
		return err;
	}

	if (val < 0 || val > 1) {
		vfe_print("Invalid value, 0~1 is expected!\n");
	} else {
		vfe_dbg_en = val;
		vfe_print("vfe_dbg_en = %ld\n", val);
	}

	return count;
}

static ssize_t vfe_dbg_lv_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	return sprintf(buf, "%u\n", vfe_dbg_lv);
}

static ssize_t vfe_dbg_lv_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	int err;
	unsigned long val;

	err = kstrtoul(buf, 10, &val);
	if (err) {
		vfe_print("Invalid size\n");
		return err;
	}

	if (val < 0 || val > 4) {
		vfe_print("Invalid value, 0~3 is expected!\n");
	} else {
		vfe_dbg_lv = val;
		vfe_print("vfe_dbg_lv = %d\n", vfe_dbg_lv);
	}

	return count;
}

static ssize_t isp_reparse_flag_show(struct device *dev,
		    struct device_attribute *attr, char *buf)
{
	return sprintf(buf, "%u\n", isp_reparse_flag);
}

static ssize_t isp_reparse_flag_store(struct device *dev,
		    struct device_attribute *attr,
		    const char *buf, size_t count)
{
	int err;
	unsigned long val;

	err = kstrtoul(buf, 10, &val);
	if (err) {
		vfe_print("Invalid size\n");
		return err;
	}

	if (val < 0 || val > 4) {
		vfe_print("Invalid value, 0~1 is expected!\n");
	} else {
		isp_reparse_flag = val;
		vfe_print("isp_reparse_flag = %ld\n", val);
	}

	return count;
}
static ssize_t vfe_dbg_dump_show(struct device *dev,
		    struct device_attribute *attr, char *buf)
{
	return sprintf(buf, "%u\n", vfe_dump);
}

static ssize_t vfe_dbg_dump_store(struct device *dev,
		    struct device_attribute *attr,
		    const char *buf, size_t count)
{
	int err;
	unsigned long val;

	err = kstrtoul(buf, 10, &val);
	if (err) {
		vfe_print("Invalid size\n");
		return err;
	}

	if (val < 0 || val > 3) {
		vfe_print("Invalid value, 0~3 is expected!\n");
	} else {
		vfe_dump = val;
		vfe_print("vfe_dump = %ld\n", val);
	}

	return count;
}

static DEVICE_ATTR(vfe_dbg_en, S_IRUGO | S_IWUSR | S_IWGRP,
		vfe_dbg_en_show, vfe_dbg_en_store);

static DEVICE_ATTR(vfe_dbg_lv, S_IRUGO | S_IWUSR | S_IWGRP,
		vfe_dbg_lv_show, vfe_dbg_lv_store);
static DEVICE_ATTR(vfe_dump, S_IRUGO | S_IWUSR | S_IWGRP,
		vfe_dbg_dump_show, vfe_dbg_dump_store);
static DEVICE_ATTR(isp_reparse_flag, S_IRUGO | S_IWUSR | S_IWGRP,
		isp_reparse_flag_show, isp_reparse_flag_store);

static struct attribute *vfe_attributes[] = {
	&dev_attr_vfe_dbg_en.attr,
	&dev_attr_vfe_dbg_lv.attr,
	&dev_attr_vfe_dump.attr,
	&dev_attr_isp_reparse_flag.attr,
	NULL
};

static struct attribute_group vfe_attribute_group = {
	.name = "vfe_attr",
	.attrs = vfe_attributes
};

static struct vfe_fmt formats[] = {
	{
		.name         = "planar YUV 422",
		.fourcc       = V4L2_PIX_FMT_YUV422P,
		.depth        = 16,
		.planes_cnt   = 3,
	},
	{
		.name         = "planar YUV 420",
		.fourcc       = V4L2_PIX_FMT_YUV420,
		.depth        = 12,
		.planes_cnt   = 3,
	},
	{
		.name         = "planar YVU 420",
		.fourcc       = V4L2_PIX_FMT_YVU420,
		.depth        = 12,
		.planes_cnt   = 3,
	},
	{
		.name         = "planar YUV 422 UV combined",
		.fourcc       = V4L2_PIX_FMT_NV16,
		.depth        = 16,
		.planes_cnt   = 2,
	},
	{
		.name         = "planar YUV 420 UV combined",
		.fourcc       = V4L2_PIX_FMT_NV12,
		.depth        = 12,
		.planes_cnt   = 2,
	},
	{
		.name         = "planar YUV 422 VU combined",
		.fourcc       = V4L2_PIX_FMT_NV61,
		.depth        = 16,
		.planes_cnt   = 2,
	},
	{
		.name         = "planar YUV 420 VU combined",
		.fourcc       = V4L2_PIX_FMT_NV21,
		.depth        = 12,
		.planes_cnt   = 2,
	},
	{
		.name         = "MB YUV420",
		.fourcc       = V4L2_PIX_FMT_HM12,
		.depth        = 12,
		.planes_cnt   = 2,
	},
	{
		.name         = "YUV422 YUYV",
		.fourcc       = V4L2_PIX_FMT_YUYV,
		.depth        = 16,
		.planes_cnt   = 1,
	},
	{
		.name         = "YUV422 YVYU",
		.fourcc       = V4L2_PIX_FMT_YVYU,
		.depth        = 16,
		.planes_cnt   = 1,
	},
	{
		.name         = "YUV422 UYVY",
		.fourcc       = V4L2_PIX_FMT_UYVY,
		.depth        = 16,
		.planes_cnt   = 1,
	},
	{
		.name         = "YUV422 VYUY",
		.fourcc       = V4L2_PIX_FMT_VYUY,
		.depth        = 16,
		.planes_cnt   = 1,
	},
	{
		.name         = "RAW Bayer BGGR 8bit",
		.fourcc       = V4L2_PIX_FMT_SBGGR8,
		.depth        = 8,
		.planes_cnt   = 1,
	},
	{
		.name         = "RAW Bayer GBRG 8bit",
		.fourcc       = V4L2_PIX_FMT_SGBRG8,
		.depth        = 8,
		.planes_cnt   = 1,
	},
	{
		.name         = "RAW Bayer GRBG 8bit",
		.fourcc       = V4L2_PIX_FMT_SGRBG8,
		.depth        = 8,
		.planes_cnt   = 1,
	},
	{
		.name         = "RAW Bayer RGGB 8bit",
		.fourcc       = V4L2_PIX_FMT_SGRBG8,
		.depth        = 8,
		.planes_cnt   = 1,
	},
	{
		.name         = "RAW Bayer BGGR 10bit",
		.fourcc       = V4L2_PIX_FMT_SBGGR10,
		.depth        = 8,
		.planes_cnt   = 1,
	},
	{
		.name         = "RAW Bayer GBRG 10bit",
		.fourcc       = V4L2_PIX_FMT_SGBRG10,
		.depth        = 8,
		.planes_cnt   = 1,
	},
	{
		.name         = "RAW Bayer GRBG 10bit",
		.fourcc       = V4L2_PIX_FMT_SGRBG10,
		.depth        = 8,
		.planes_cnt   = 1,
	},
	{
		.name         = "RAW Bayer RGGB 10bit",
		.fourcc       = V4L2_PIX_FMT_SGRBG10,
		.depth        = 8,
		.planes_cnt   = 1,
	},
	{
		.name         = "RAW Bayer BGGR 12bit",
		.fourcc       = V4L2_PIX_FMT_SBGGR12,
		.depth        = 8,
		.planes_cnt   = 1,
	},
	{
		.name         = "RAW Bayer GBRG 12bit",
		.fourcc       = V4L2_PIX_FMT_SGBRG12,
		.depth        = 8,
		.planes_cnt   = 1,
	},
	{
		.name         = "RAW Bayer GRBG 12bit",
		.fourcc       = V4L2_PIX_FMT_SGRBG12,
		.depth        = 8,
		.planes_cnt   = 1,
	},
	{
		.name         = "RAW Bayer RGGB 12bit",
		.fourcc       = V4L2_PIX_FMT_SGRBG12,
		.depth        = 8,
		.planes_cnt   = 1,
	},
};

u32 try_yuv422_bus[] = {
	MEDIA_BUS_FMT_VYUY10_2X10,
	MEDIA_BUS_FMT_UYVY10_2X10,
	MEDIA_BUS_FMT_YUYV10_2X10,
	MEDIA_BUS_FMT_YVYU10_2X10,
	MEDIA_BUS_FMT_UYVY8_2X8,
	MEDIA_BUS_FMT_VYUY8_2X8,
	MEDIA_BUS_FMT_YUYV8_2X8,
	MEDIA_BUS_FMT_YVYU8_2X8,
	MEDIA_BUS_FMT_YUYV10_1X20,
	MEDIA_BUS_FMT_YVYU10_1X20,
	MEDIA_BUS_FMT_UYVY8_1X16,
	MEDIA_BUS_FMT_VYUY8_1X16,
	MEDIA_BUS_FMT_YUYV8_1X16,
	MEDIA_BUS_FMT_YVYU8_1X16,
	MEDIA_BUS_FMT_AYUV8_1X32,
};

u32 try_yuv420_bus[] = {
	MEDIA_BUS_FMT_VYUY10_1X20,
	MEDIA_BUS_FMT_UYVY10_1X20,
};

u32 try_bayer_rgb_bus[] = {
	MEDIA_BUS_FMT_SBGGR12_1X12,
	MEDIA_BUS_FMT_SGBRG12_1X12,
	MEDIA_BUS_FMT_SGRBG12_1X12,
	MEDIA_BUS_FMT_SRGGB12_1X12,
	MEDIA_BUS_FMT_SBGGR10_1X10,
	MEDIA_BUS_FMT_SGBRG10_1X10,
	MEDIA_BUS_FMT_SGRBG10_1X10,
	MEDIA_BUS_FMT_SRGGB10_1X10,
	MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8,
	MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8,
	MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8,
	MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8,
	MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE,
	MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE,
	MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE,
	MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE,
	MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8,
	MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8,
	MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8,
	MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8,
	MEDIA_BUS_FMT_SBGGR8_1X8,
	MEDIA_BUS_FMT_SGBRG8_1X8,
	MEDIA_BUS_FMT_SGRBG8_1X8,
	MEDIA_BUS_FMT_SRGGB8_1X8,
};

u32 try_rgb565_bus[] = {
	MEDIA_BUS_FMT_ARGB8888_1X32,
	MEDIA_BUS_FMT_BGR565_2X8_BE,
	MEDIA_BUS_FMT_BGR565_2X8_LE,
	MEDIA_BUS_FMT_RGB565_2X8_BE,
	MEDIA_BUS_FMT_RGB565_2X8_LE,
};

u32 try_rgb888_bus[] = {
	MEDIA_BUS_FMT_RBG888_1X24,
};

struct vfe_fmt_code vfe_fmt_code[] = {
	{
		.bus_name = "bayer",
		.pix_name = "yuv422/yuv420",
		.mbus_code = try_bayer_rgb_bus,
		.size = ARRAY_SIZE(try_bayer_rgb_bus),
	},
	{
		.bus_name = "yuv422",
		.pix_name = "yuv422/yuv420",
		.mbus_code = try_yuv422_bus,
		.size = ARRAY_SIZE(try_yuv422_bus),
	},
	{
		.bus_name = "yuv420",
		.pix_name = "yuv422/yuv420",
		.mbus_code = try_yuv420_bus,
		.size = ARRAY_SIZE(try_yuv420_bus),
	},
	{
		.bus_name = "rgb565",
		.pix_name = "rgb565",
		.mbus_code = try_rgb565_bus,
		.size = ARRAY_SIZE(try_rgb565_bus),
	},
	{
		.bus_name = "rgb888",
		.pix_name = "rgb888/prgb888",
		.mbus_code = try_rgb888_bus,
		.size = ARRAY_SIZE(try_rgb888_bus),
	},
};

static int isp_resource_request(struct vfe_dev *dev)
{
	unsigned int isp_used_flag = 0, i;
	void *pa_base, *va_base, *dma_base;
	int ret;

	/* requeset for isp table and statistic buffer */
	for (i = 0; i < dev->dev_qty; i++) {
		if (dev->ccm_cfg[i]->is_isp_used && dev->ccm_cfg[i]->is_bayer_raw) {
			dev->isp_lut_tbl_buf_mm[i].size = ISP_LINEAR_LUT_LENS_GAMMA_MEM_SIZE;
			ret = os_mem_alloc(&dev->pdev->dev, &dev->isp_lut_tbl_buf_mm[i]);
			if (!ret) {
				pa_base = dev->isp_lut_tbl_buf_mm[i].phy_addr;
				va_base = dev->isp_lut_tbl_buf_mm[i].vir_addr;
				dma_base = dev->isp_lut_tbl_buf_mm[i].dma_addr;
				dev->isp_tbl_addr[i].isp_def_lut_tbl_paddr = (void *)(pa_base + ISP_LUT_MEM_OFS);
				dev->isp_tbl_addr[i].isp_def_lut_tbl_dma_addr = (void *)(dma_base + ISP_LUT_MEM_OFS);
				dev->isp_tbl_addr[i].isp_def_lut_tbl_vaddr = (void *)(va_base + ISP_LUT_MEM_OFS);
				dev->isp_tbl_addr[i].isp_lsc_tbl_paddr = (void *)(pa_base + ISP_LENS_MEM_OFS);
				dev->isp_tbl_addr[i].isp_lsc_tbl_dma_addr = (void *)(dma_base + ISP_LENS_MEM_OFS);
				dev->isp_tbl_addr[i].isp_lsc_tbl_vaddr = (void *)(va_base + ISP_LENS_MEM_OFS);
				dev->isp_tbl_addr[i].isp_gamma_tbl_paddr = (void *)(pa_base + ISP_GAMMA_MEM_OFS);
				dev->isp_tbl_addr[i].isp_gamma_tbl_dma_addr = (void *)(dma_base + ISP_GAMMA_MEM_OFS);
				dev->isp_tbl_addr[i].isp_gamma_tbl_vaddr = (void *)(va_base + ISP_GAMMA_MEM_OFS);

				dev->isp_tbl_addr[i].isp_linear_tbl_paddr = (void *)(pa_base + ISP_LINEAR_MEM_OFS);
				dev->isp_tbl_addr[i].isp_linear_tbl_dma_addr = (void *)(dma_base + ISP_LINEAR_MEM_OFS);
				dev->isp_tbl_addr[i].isp_linear_tbl_vaddr = (void *)(va_base + ISP_LINEAR_MEM_OFS);
				vfe_dbg(0, "isp_def_lut_tbl_vaddr[%d] = %p\n", i, dev->isp_tbl_addr[i].isp_def_lut_tbl_vaddr);
				vfe_dbg(0, "isp_lsc_tbl_vaddr[%d] = %p\n", i, dev->isp_tbl_addr[i].isp_lsc_tbl_vaddr);
				vfe_dbg(0, "isp_gamma_tbl_vaddr[%d] = %p\n", i, dev->isp_tbl_addr[i].isp_gamma_tbl_vaddr);
			} else {
				vfe_err("isp lut_lens_gamma table request pa failed!\n");
				return -ENOMEM;
			}
		}

		if (dev->ccm_cfg[i]->is_isp_used && dev->ccm_cfg[i]->is_bayer_raw) {
			dev->isp_drc_tbl_buf_mm[i].size = ISP_DRC_DISC_MEM_SIZE;
			ret = os_mem_alloc(&dev->pdev->dev, &dev->isp_drc_tbl_buf_mm[i]);
			if (!ret) {
				pa_base = dev->isp_drc_tbl_buf_mm[i].phy_addr;
				va_base = dev->isp_drc_tbl_buf_mm[i].vir_addr;
				dma_base = dev->isp_drc_tbl_buf_mm[i].dma_addr;

				dev->isp_tbl_addr[i].isp_drc_tbl_paddr = (void *)(pa_base + ISP_DRC_MEM_OFS);
				dev->isp_tbl_addr[i].isp_drc_tbl_dma_addr = (void *)(dma_base + ISP_DRC_MEM_OFS);
				dev->isp_tbl_addr[i].isp_drc_tbl_vaddr = (void *)(va_base + ISP_DRC_MEM_OFS);

				dev->isp_tbl_addr[i].isp_disc_tbl_paddr = (void *)(pa_base + ISP_DISC_MEM_OFS);
				dev->isp_tbl_addr[i].isp_disc_tbl_dma_addr = (void *)(dma_base + ISP_DISC_MEM_OFS);
				dev->isp_tbl_addr[i].isp_disc_tbl_vaddr = (void *)(va_base + ISP_DISC_MEM_OFS);

				vfe_dbg(0, "isp_drc_tbl_vaddr[%d] = %p\n", i, dev->isp_tbl_addr[i].isp_drc_tbl_vaddr);
			} else {
				vfe_err("isp drc table request pa failed!\n");
				return -ENOMEM;
			}
		}
	}

	for (i = 0; i < dev->dev_qty; i++) {
		if (dev->ccm_cfg[i]->is_isp_used && dev->ccm_cfg[i]->is_bayer_raw) {
			isp_used_flag = 1;
			break;
		}
	}

	if (isp_used_flag) {
		for (i = 0; i < MAX_ISP_STAT_BUF; i++) {
			dev->isp_stat_buf_mm[i].size = ISP_STAT_TOTAL_SIZE;
			ret = os_mem_alloc(&dev->pdev->dev, &dev->isp_stat_buf_mm[i]);
			if (!ret) {
				pa_base = dev->isp_stat_buf_mm[i].phy_addr;
				va_base = dev->isp_stat_buf_mm[i].vir_addr;
				dma_base = dev->isp_stat_buf_mm[i].dma_addr;
				INIT_LIST_HEAD(&dev->isp_stat_bq.isp_stat[i].queue);
				dev->isp_stat_bq.isp_stat[i].id = i;
				dev->isp_stat_bq.isp_stat[i].paddr = (void *)(pa_base);
				dev->isp_stat_bq.isp_stat[i].dma_addr = (void *)(dma_base);
				dev->isp_stat_bq.isp_stat[i].isp_stat_buf.stat_buf = (void *)(va_base);
				dev->isp_stat_bq.isp_stat[i].isp_stat_buf.buf_size = ISP_STAT_TOTAL_SIZE;
				dev->isp_stat_bq.isp_stat[i].isp_stat_buf.buf_status = BUF_IDLE;
				vfe_dbg(0, "dev->isp_stat_bq.isp_stat[i].isp_stat_buf.stat_buf[%d] = %p\n", i, dev->isp_stat_bq.isp_stat[i].isp_stat_buf.stat_buf);
			} else {
				vfe_err("isp statistic buffer request pa failed!\n");
				return -ENOMEM;
			}
		}
	}

	return 0;
}
static int vfe_device_regulator_get(struct device *dev, struct ccm_config *ccm_cfg, int num);
static int vfe_device_regulator_put(struct ccm_config *ccm_cfg);
static int vfe_set_sensor_power_on(struct vfe_dev *dev);
static int vfe_set_sensor_power_off(struct vfe_dev *dev);

static void isp_resource_release(struct vfe_dev *dev)
{
	unsigned int isp_used_flag = 0, i;

	/* release isp table and statistic buffer */
	for (i = 0; i < dev->dev_qty; i++) {
		if (dev->ccm_cfg[i]->is_isp_used && dev->ccm_cfg[i]->is_bayer_raw) {
			os_mem_free(&dev->pdev->dev, &dev->isp_lut_tbl_buf_mm[i]);
			os_mem_free(&dev->pdev->dev, &dev->isp_drc_tbl_buf_mm[i]);
		}
	}

	for (i = 0; i < dev->dev_qty; i++) {
		if (dev->ccm_cfg[i]->is_isp_used && dev->ccm_cfg[i]->is_bayer_raw) {
			isp_used_flag = 1;
			break;
		}
	}

	if (isp_used_flag) {
		for (i = 0; i < MAX_ISP_STAT_BUF; i++) {
			os_mem_free(&dev->pdev->dev, &dev->isp_stat_buf_mm[i]);
		}
	}
}

static int vfe_is_generating(struct vfe_dev *dev)
{
	int ret;
	unsigned long flags = 0;

	spin_lock_irqsave(&dev->slock, flags);
	ret = test_bit(0, &dev->generating);
	spin_unlock_irqrestore(&dev->slock, flags);
	return ret;
}

static void vfe_start_generating(struct vfe_dev *dev)
{
	unsigned long flags = 0;

	spin_lock_irqsave(&dev->slock, flags);
	set_bit(0, &dev->generating);
	spin_unlock_irqrestore(&dev->slock, flags);
}

static void vfe_stop_generating(struct vfe_dev *dev)
{
	unsigned long flags = 0;

	spin_lock_irqsave(&dev->slock, flags);
	dev->first_flag[dev->cur_ch] = 0;
	clear_bit(0, &dev->generating);
	spin_unlock_irqrestore(&dev->slock, flags);
}

static int vfe_is_opened(struct vfe_dev *dev)
{
	 int ret;

	 mutex_lock(&dev->opened_lock);
	 ret = test_bit(0, &dev->opened);
	 mutex_unlock(&dev->opened_lock);
	 return ret;
}

static void vfe_start_opened(struct vfe_dev *dev)
{
	 mutex_lock(&dev->opened_lock);
	 set_bit(0, &dev->opened);
	 mutex_unlock(&dev->opened_lock);
}

static void vfe_stop_opened(struct vfe_dev *dev)
{
	 mutex_lock(&dev->opened_lock);
	 clear_bit(0, &dev->opened);
	 mutex_unlock(&dev->opened_lock);
}

static void update_ccm_info(struct vfe_dev *dev, struct ccm_config *ccm_cfg)
{
	dev->sd			= ccm_cfg->sd;
	dev->sd_act		= ccm_cfg->sd_act;
	dev->is_isp_used	= ccm_cfg->is_isp_used;
	dev->is_bayer_raw	= ccm_cfg->is_bayer_raw;
	dev->power		= &ccm_cfg->power;
	dev->gpio		= ccm_cfg->gpio;
	dev->flash_used		= ccm_cfg->flash_used;
	dev->flash_type		= ccm_cfg->flash_type;

	/* print change */
	vfe_dbg(0, "ccm_cfg pt = %p\n", ccm_cfg);
	vfe_dbg(0, "ccm_cfg->sd = %p\n", ccm_cfg->sd);
	vfe_dbg(0, "module is_isp_used = %d is_bayer_raw= %d\n", dev->is_isp_used, dev->is_bayer_raw);
}

static void update_isp_setting(struct vfe_dev *dev)
{
	dev->isp_3a_result_pt = &dev->isp_3a_result[dev->input];
	dev->isp_gen_set_pt = dev->isp_gen_set[dev->input];
	dev->isp_gen_set_pt->module_cfg.isp_platform_id = dev->platform_id;
	if (dev->is_bayer_raw) {
		mutex_init(&dev->isp_3a_result_mutex);
		dev->isp_gen_set_pt->module_cfg.lut_src0_table = dev->isp_tbl_addr[dev->input].isp_def_lut_tbl_vaddr;
		dev->isp_gen_set_pt->module_cfg.gamma_table = dev->isp_tbl_addr[dev->input].isp_gamma_tbl_vaddr;
		dev->isp_gen_set_pt->module_cfg.lens_table = dev->isp_tbl_addr[dev->input].isp_lsc_tbl_vaddr;
		dev->isp_gen_set_pt->module_cfg.linear_table = dev->isp_tbl_addr[dev->input].isp_linear_tbl_vaddr;
		dev->isp_gen_set_pt->module_cfg.disc_table = dev->isp_tbl_addr[dev->input].isp_disc_tbl_vaddr;
		if (dev->is_isp_used)
			bsp_isp_update_lut_lens_gamma_table(&dev->isp_tbl_addr[dev->input]);
	}
	dev->isp_gen_set_pt->module_cfg.drc_table = dev->isp_tbl_addr[dev->input].isp_drc_tbl_vaddr;
	if (dev->is_isp_used)
		bsp_isp_update_drc_table(&dev->isp_tbl_addr[dev->input]);
}

static inline void vfe_set_addr(struct vfe_dev *dev, struct vfe_buffer *buffer, int ch)
{
	dma_addr_t addr_org;
	struct vb2_buffer *vb_buf = &buffer->vb.vb2_buf;

	if (dev->special_active == 1) {
		if (buffer == NULL || buffer->paddr == NULL) {
			vfe_err("%s buffer is NULL!\n", __func__);
			return;
		}
	} else {
		if (vb_buf == NULL || vb_buf->planes[0].mem_priv == NULL) {
			vfe_err("vb_buf->priv is NULL!\n");
			return;
		}
	}

	if (dev->special_active == 1)
		addr_org = (dma_addr_t)buffer->paddr;
	else
		addr_org = vb2_dma_contig_plane_dma_addr(vb_buf, 0)
				- CPU_DRAM_PADDR_ORG + HW_DMA_OFFSET;

	if (dev->is_isp_used) {
		sunxi_isp_set_output_addr(dev->isp_sd, addr_org);
	} else {
#if defined(CH_OUTPUT_IN_DIFFERENT_VIDEO)
		bsp_csi_set_ch_addr(dev->csi_sel, ch, addr_org);
#else
		bsp_csi_set_addr(dev->csi_sel, addr_org);
#endif
	}
	vfe_dbg(3, "csi_buf_addr_orginal=%pa\n", &addr_org);
}

static void vfe_init_isp_log(struct vfe_dev *dev)
{
	if (isp_log == 1) {
		fp_dbg = cfg_open_file(LogFileName);
		dev->isp_gen_set[0]->enable_log = 1;
		dev->isp_gen_set[1]->enable_log = 1;
		if (IS_ERR(fp_dbg))
			vfe_err("open log.txt error.");
	} else {
		dev->isp_gen_set[0]->enable_log = 0;
		dev->isp_gen_set[1]->enable_log = 0;
	}

}
static void vfe_exit_isp_log(struct vfe_dev *dev)
{
	if (isp_log == 1)
		cfg_close_file(fp_dbg);
}
static void vfe_dump_isp_log(struct vfe_dev *dev)
{

	/* dump isp log. */
	if (isp_log == 1 && (frame_cnt % 4 == 0)) {
		if (cfg_write_file(fp_dbg, dev->isp_gen_set_pt->stat.hist_buf, ISP_STAT_HIST_MEM_SIZE) < 0) {
			vfe_err("dump isp hist faild.");
			return;
		}
		if (cfg_write_file(fp_dbg, dev->isp_gen_set_pt->stat.ae_buf, ISP_STAT_AE_MEM_SIZE) < 0) {
			vfe_err("dump isp ae faild.");
		}
		if (cfg_write_file(fp_dbg, (char *)dev->isp_gen_set_pt->awb_buf, 3*ISP_STAT_AWB_WIN_MEM_SIZE) < 0) {
			vfe_err("dump awb log faild.");
		}
		/*
		if (cfg_write_file(fp_dbg, dev->isp_gen_set_pt->stat.af_buf, ISP_STAT_AF_MEM_SIZE) < 0) {
			vfe_err("dump isp log faild.");
		}
		if (cfg_write_file(fp_dbg, "0123456789abcdef\n", 16) < 0) {
			vfe_err("/system/etc/hawkview/log.txt write test failed.");
		}
		*/
	}
}

static void isp_isr_bh_handle(struct work_struct *work)
{
	struct actuator_ctrl_word_t  vcm_ctrl;
	struct vfe_dev *dev = container_of(work, struct vfe_dev, isp_isr_bh_task);

	FUNCTION_LOG;
	if (vfe_dump & DUMP_ISP) {
		if (9 == (frame_cnt % 10)) {
			sunxi_isp_dump_regs(dev->isp_sd);
		}
	}
	if (dev->is_bayer_raw) {
		mutex_lock(&dev->isp_3a_result_mutex);
		if (isp_reparse_flag == 1) {
			vfe_print("ISP reparse ini file!\n");
			if (read_ini_info(dev, dev->input, "/system/etc/hawkview/")) {
				vfe_warn("ISP reparse ini fail, please check isp config!\n");
				goto ISP_REPARSE_END;
			}
			isp_param_init(dev->isp_gen_set_pt);
			isp_config_init(dev->isp_gen_set_pt);
			isp_module_init(dev->isp_gen_set_pt, dev->isp_3a_result_pt);
ISP_REPARSE_END:
			isp_reparse_flag = 0;
		}
		if (isp_reparse_flag == 2) {
			vfe_reg_set((void __iomem *) (unsigned long)(ISP_REGS_BASE+0x10), (1 << 20));
		}
		if (isp_reparse_flag == 3) {
			vfe_reg_clr_set((void __iomem *) (unsigned long)(ISP_REGS_BASE+0x10), (0xF << 16), (1 << 16));
			vfe_reg_set((void __iomem *) (unsigned long)(ISP_REGS_BASE+0x10), (1 << 20));
		}
		if (isp_reparse_flag == 4) {
			/* vfe_reg_clr_set(IO_ADDRESS(ISP_REGS_BASE+0x10), (0xF << 16), (1 << 16)); */
			vfe_reg_clr((void __iomem *) (unsigned long)(ISP_REGS_BASE+0x10), (1 << 20));
			vfe_reg_clr((void __iomem *) (unsigned long)(ISP_REGS_BASE+0x10), (0xF << 16));
		}
		vfe_dump_isp_log(dev);
		isp_isr(dev->isp_gen_set_pt, dev->isp_3a_result_pt);
		if ((dev->ctrl_para.prev_focus_pos != dev->isp_3a_result_pt->real_vcm_pos  ||
				dev->isp_gen_set_pt->isp_ini_cfg.isp_test_settings.isp_test_mode != 0 ||
				dev->isp_gen_set_pt->isp_ini_cfg.isp_test_settings.af_en == 0) && dev->sd_act) {
			vcm_ctrl.code =  dev->isp_3a_result_pt->real_vcm_pos;
			vcm_ctrl.sr = 0x0;
			if (v4l2_subdev_call(dev->sd_act, core, ioctl, ACT_SET_CODE, &vcm_ctrl)) {
				vfe_warn("set vcm error!\n");
			} else {
				dev->ctrl_para.prev_focus_pos = dev->isp_3a_result_pt->real_vcm_pos;
			}
		}

		mutex_unlock(&dev->isp_3a_result_mutex);
	} else {
		isp_isr(dev->isp_gen_set_pt, NULL);
	}

	FUNCTION_LOG;
}

int set_sensor_shutter(struct vfe_dev *dev, int shutter)
{
	struct v4l2_control ctrl;

	if (shutter <= 0)
		return -EINVAL;

	ctrl.id = V4L2_CID_EXPOSURE;
	ctrl.value = shutter;
	if (v4l2_s_ctrl(NULL, dev->sd->ctrl_handler, &ctrl) != 0) {
		vfe_err("set sensor exposure line error!\n");
		return -EPERM;
	} else
		dev->ctrl_para.prev_exp_line = shutter;

	return 0;
}

int set_sensor_gain(struct vfe_dev *dev, int gain)
{
	struct v4l2_control ctrl;

	if (gain < 16)
		return -EINVAL;

	ctrl.id = V4L2_CID_GAIN;
	ctrl.value = gain;
	if (v4l2_s_ctrl(NULL, dev->sd->ctrl_handler, &ctrl) != 0) {
		vfe_err("set sensor gain error!\n");
		return -EPERM;
	} else
		dev->ctrl_para.prev_ana_gain = gain;

	return 0;
}

int set_sensor_shutter_and_gain(struct vfe_dev *dev)
{
	struct sensor_exp_gain exp_gain;

	exp_gain.exp_val = dev->isp_3a_result_pt->exp_line_num;
	exp_gain.gain_val = dev->isp_3a_result_pt->exp_analog_gain;
	if (exp_gain.gain_val < 16 || exp_gain.exp_val <= 0)
		return -EINVAL;

	if (v4l2_subdev_call(dev->sd, core, ioctl, ISP_SET_EXP_GAIN, &exp_gain) != 0) {
		vfe_warn("set ISP_SET_EXP_GAIN error, set V4L2_CID_EXPOSURE!\n");
		return -EPERM;
	} else {
		dev->ctrl_para.prev_exp_line = exp_gain.exp_val;
		dev->ctrl_para.prev_ana_gain = exp_gain.gain_val;
	}

	return 0;
}

static int isp_s_ctrl_torch_open(struct vfe_dev *dev)
{
	if (dev->isp_gen_set_pt->exp_settings.flash_mode == FLASH_MODE_OFF)
		return 0;

	if (((dev->isp_gen_set_pt->exp_settings.tbl_cnt > (dev->isp_gen_set_pt->exp_settings.tbl_max_ind - 25)) ||
			dev->isp_gen_set_pt->exp_settings.flash_mode == FLASH_MODE_ON)) {
		vfe_dbg(0, "open flash when nigth mode\n");
		io_set_flash_ctrl(dev->flash_sd, SW_CTRL_TORCH_ON);
		touch_flash_flag = 1;
	}

	return 0;
}

static int isp_s_ctrl_torch_close(struct vfe_dev *dev)
{
	if (dev->isp_gen_set_pt->exp_settings.flash_mode == FLASH_MODE_OFF)
		return 0;

	if (touch_flash_flag == 1) {
		vfe_dbg(0, "close flash when nigth mode\n");
		io_set_flash_ctrl(dev->flash_sd, SW_CTRL_FLASH_OFF);
		touch_flash_flag = 0;
	}

	return 0;
}

static int isp_streamoff_torch_and_flash_close(struct vfe_dev *dev)
{
	if (dev->isp_gen_set_pt->exp_settings.flash_mode == FLASH_MODE_OFF)
		return 0;

	if (touch_flash_flag == 1 || dev->isp_gen_set_pt->exp_settings.flash_open == 1) {
		vfe_dbg(0, "close flash when nigth mode\n");
		io_set_flash_ctrl(dev->flash_sd, SW_CTRL_FLASH_OFF);
		touch_flash_flag = 0;
	}

	return 0;
}

static int isp_set_capture_flash(struct vfe_dev *dev)
{
	if (dev->isp_gen_set_pt->exp_settings.flash_mode == FLASH_MODE_OFF)
		return 0;

	if (dev->isp_gen_set_pt->take_pic_start_cnt == 1) {
		if (dev->isp_gen_set_pt->exp_settings.tbl_cnt > (dev->isp_gen_set_pt->exp_settings.tbl_max_ind - 40) ||
				dev->isp_gen_set_pt->exp_settings.flash_mode == FLASH_MODE_ON) {
			vfe_dbg(0, "open torch when nigth mode\n");
			io_set_flash_ctrl(dev->flash_sd, SW_CTRL_TORCH_ON);
			dev->isp_gen_set_pt->exp_settings.flash_open = 1;
		}
	}

	if (dev->isp_gen_set_pt->exp_settings.flash_open == 1 && dev->isp_gen_set_pt->take_pic_start_cnt ==
					dev->isp_gen_set_pt->isp_ini_cfg.isp_tunning_settings.flash_delay_frame) {
		vfe_dbg(0, "open flash when nigth mode\n");
		dev->isp_gen_set_pt->exp_settings.exposure_lock = ISP_TRUE;
		ev_cumul = get_pre_ev_cumul(dev->isp_gen_set_pt, dev->isp_3a_result_pt);
		if (ev_cumul >= 100) {
			dev->isp_gen_set_pt->exp_settings.tbl_cnt = CLIP(dev->isp_gen_set_pt->exp_settings.expect_tbl_cnt, 1,
						dev->isp_gen_set_pt->exp_settings.tbl_max_ind);
		} else if (ev_cumul >= dev->isp_gen_set_pt->isp_ini_cfg.isp_tunning_settings.flash_gain * 100 / 256 && ev_cumul < 100) {
			dev->isp_gen_set_pt->exp_settings.tbl_cnt = CLIP(dev->isp_gen_set_pt->exp_settings.expect_tbl_cnt, 1,
						dev->isp_gen_set_pt->exp_settings.tbl_max_ind);
		} else if (ev_cumul >= -25 && ev_cumul < dev->isp_gen_set_pt->isp_ini_cfg.isp_tunning_settings.flash_gain * 100 / 256) {
			dev->isp_gen_set_pt->exp_settings.tbl_cnt = CLIP(dev->isp_gen_set_pt->exp_settings.expect_tbl_cnt +
						ev_cumul * dev->isp_gen_set_pt->isp_ini_cfg.isp_tunning_settings.flash_gain / 256, 1,
						dev->isp_gen_set_pt->exp_settings.tbl_max_ind);
		} else {
			dev->isp_gen_set_pt->exp_settings.tbl_cnt = CLIP(dev->isp_gen_set_pt->exp_settings.expect_tbl_cnt +
						ev_cumul * dev->isp_gen_set_pt->isp_ini_cfg.isp_tunning_settings.flash_gain / 256, 1,
						dev->isp_gen_set_pt->exp_settings.tbl_max_ind);
		}
		config_sensor_next_exposure(dev->isp_gen_set_pt, dev->isp_3a_result_pt);
		io_set_flash_ctrl(dev->flash_sd, SW_CTRL_FLASH_OFF);
	}

	if (dev->isp_gen_set_pt->exp_settings.flash_open == 1 && dev->isp_gen_set_pt->take_pic_start_cnt ==
					dev->isp_gen_set_pt->isp_ini_cfg.isp_tunning_settings.flash_delay_frame + 1) {
		io_set_flash_ctrl(dev->flash_sd, SW_CTRL_FLASH_ON);
	}

	if (dev->isp_gen_set_pt->take_pic_start_cnt == 7 + dev->isp_gen_set_pt->isp_ini_cfg.isp_tunning_settings.flash_delay_frame) {
		vfe_dbg(0, "close flash when nigth mode\n");
		io_set_flash_ctrl(dev->flash_sd, SW_CTRL_FLASH_OFF);
		dev->isp_gen_set_pt->exp_settings.tbl_cnt = CLIP(dev->isp_gen_set_pt->exp_settings.expect_tbl_cnt,
				1, dev->isp_gen_set_pt->exp_settings.tbl_max_ind);
		dev->isp_gen_set_pt->exp_settings.exposure_lock = ISP_FALSE;
		dev->isp_gen_set_pt->exp_settings.flash_open = 0;
	}

	if (dev->isp_gen_set_pt->exp_settings.flash_open == 0 && touch_flash_flag == 1 &&
			(dev->isp_3a_result_pt->af_status == AUTO_FOCUS_STATUS_REACHED ||
			dev->isp_3a_result_pt->af_status == AUTO_FOCUS_STATUS_FAILED ||
			dev->isp_3a_result_pt->af_status == AUTO_FOCUS_STATUS_FINDED)) {
		vfe_dbg(0, "close flash when touch nigth mode\n");
		io_set_flash_ctrl(dev->flash_sd, SW_CTRL_FLASH_OFF);
		touch_flash_flag = 0;
	}

	return 0;
}

static void isp_isr_set_sensor_handle(struct work_struct *work)
{
	struct vfe_dev *dev = container_of(work, struct vfe_dev, isp_isr_set_sensor_task);

	if (dev->is_bayer_raw) {
		mutex_lock(&dev->isp_3a_result_mutex);
		isp_set_capture_flash(dev);
		if (dev->isp_gen_set_pt->isp_ini_cfg.isp_3a_settings.adaptive_frame_rate == 1 ||
				dev->isp_gen_set_pt->isp_ini_cfg.isp_3a_settings.force_frame_rate == 1 ||
				dev->isp_gen_set_pt->isp_ini_cfg.isp_3a_settings.high_quality_mode_en == 1) {
			vfe_dbg(0, "combinate shutter = %d, gain =%d\n", dev->isp_3a_result_pt->exp_line_num,
					dev->isp_3a_result_pt->exp_analog_gain);
			if (set_sensor_shutter_and_gain(dev) != 0) {
				set_sensor_shutter(dev, dev->isp_3a_result_pt->exp_line_num);
				set_sensor_gain(dev, dev->isp_3a_result_pt->exp_analog_gain);
			}
		} else {
			vfe_dbg(0, "separate shutter = %d, gain =%d\n", dev->isp_3a_result_pt->exp_line_num/16,
					dev->isp_3a_result_pt->exp_analog_gain);
			set_sensor_shutter(dev, dev->isp_3a_result_pt->exp_line_num);
			set_sensor_gain(dev, dev->isp_3a_result_pt->exp_analog_gain);
		}
		mutex_unlock(&dev->isp_3a_result_mutex);
	}
}

static void vfe_isp_stat_parse(struct isp_gen_settings *isp_gen)
{
	unsigned long buffer_addr = (unsigned long)isp_gen->stat.stat_buf_whole->stat_buf;

	isp_gen->stat.hist_buf = (void *) (buffer_addr);
	isp_gen->stat.ae_buf =  (void *) (buffer_addr + ISP_STAT_AE_MEM_OFS);
	isp_gen->stat.awb_buf = (void *) (buffer_addr + ISP_STAT_AWB_MEM_OFS);
	isp_gen->stat.af_buf = (void *) (buffer_addr + ISP_STAT_AF_MEM_OFS);
	isp_gen->stat.afs_buf = (void *) (buffer_addr + ISP_STAT_AFS_MEM_OFS);
	isp_gen->stat.awb_win_buf = (void *) (buffer_addr + ISP_STAT_AWB_WIN_MEM_OFS);
}

/*
 *  the interrupt routine
 */

static irqreturn_t vfe_isr(int irq, void *priv)
{
	int i;
	unsigned long flags;
	struct vfe_buffer *buf;
	struct vfe_dev *dev = (struct vfe_dev *)priv;
	struct vfe_dmaqueue *dma_q = &dev->vidq[dev->cur_ch];
	struct vfe_dmaqueue *done = NULL;
	int need_callback = 0, current_ch = 0;
	struct csi_int_status status;
	struct vfe_isp_stat_buf_queue *isp_stat_bq = &dev->isp_stat_bq;
	struct vfe_isp_stat_buf *stat_buf_pt;
//	struct timeval timestamp;

	FUNCTION_LOG;

	if (dev->special_active == 1) {
		dma_q = &dev->vidq_special;
		done = &dev->done_special;
		need_callback = 0;
	}

	if (vfe_is_generating(dev) == 0) {
		bsp_csi_int_clear_status(dev->csi_sel, dev->cur_ch, CSI_INT_ALL);
		if (dev->is_isp_used)
			bsp_isp_clr_irq_status(ISP_IRQ_EN_ALL);

		return IRQ_HANDLED;
	}

	FUNCTION_LOG;
	spin_lock_irqsave(&dev->slock, flags);
	FUNCTION_LOG;

#if defined(CH_OUTPUT_IN_DIFFERENT_VIDEO)
	for (i = 0; i < MAX_CH_NUM; i++) {
		bsp_csi_int_get_status(dev->csi_sel, i, &status);
		if (status.frame_done == 1) {
			current_ch = i;
			dma_q = &dev->vidq[current_ch];
			break;
		}
	}
#else
	bsp_csi_int_get_status(dev->csi_sel, dev->cur_ch, &status);
	current_ch = dev->cur_ch;
	dma_q = &dev->vidq[current_ch];
#endif
	vfe_dbg(0, "csi ch %d interrupt, dev->cur_ch is %d!\n", current_ch, dev->cur_ch);

	if ((status.capture_done == 0) && (status.frame_done == 0) && (status.vsync_trig == 0)) {
		vfe_print("enter vfe int for nothing\n");
		bsp_csi_int_clear_status(dev->csi_sel, current_ch, CSI_INT_ALL);
		if (dev->is_isp_used)
			bsp_isp_clr_irq_status(ISP_IRQ_EN_ALL);

		spin_unlock_irqrestore(&dev->slock, flags);
		return IRQ_HANDLED;
	}
	if (dev->is_isp_used && dev->is_bayer_raw) {
		/* update_sensor_setting: */
		if (status.vsync_trig) {
			if ((dev->capture_mode == V4L2_MODE_VIDEO) || (dev->capture_mode == V4L2_MODE_PREVIEW)) {
				vfe_dbg(3, "call set sensor task schedule!\n");
				schedule_work(&dev->isp_isr_set_sensor_task);
			}
			bsp_csi_int_clear_status(dev->csi_sel, current_ch, CSI_INT_VSYNC_TRIG);
			spin_unlock_irqrestore(&dev->slock, flags);
			return IRQ_HANDLED;
		}
	}

	if (vfe_dump & DUMP_CSI) {
		if (5 == frame_cnt % 10) {
			sunxi_csi_dump_regs(dev->csi_sd);
		}
	}
	frame_cnt++;

	/* exception handle: */
	if ((status.buf_0_overflow) || (status.buf_1_overflow) || (status.buf_2_overflow) || (status.hblank_overflow)) {
		if ((status.buf_0_overflow) || (status.buf_1_overflow) || (status.buf_2_overflow)) {
			bsp_csi_int_clear_status(dev->csi_sel, current_ch,
					CSI_INT_BUF_0_OVERFLOW |
					CSI_INT_BUF_1_OVERFLOW |
					CSI_INT_BUF_2_OVERFLOW);
			vfe_err("fifo overflow\n");
		}
		if (status.hblank_overflow) {
			bsp_csi_int_clear_status(dev->csi_sel, current_ch, CSI_INT_HBLANK_OVERFLOW);
			vfe_err("hblank overflow\n");
		}
		vfe_err("reset csi module\n");
		bsp_csi_reset(dev->csi_sel);
		if (dev->is_isp_used)
			goto isp_exp_handle;
		else
			goto unlock;
	}
isp_exp_handle:
	if (dev->is_isp_used) {
		if (bsp_isp_get_irq_status(SRC0_FIFO_INT_EN)) {
			vfe_err("isp source0 fifo overflow\n");
			bsp_isp_clr_irq_status(SRC0_FIFO_INT_EN);
			goto unlock;
		}
	}
	vfe_dbg(3, "status vsync = %d, framedone = %d, capdone = %d\n",
			status.vsync_trig, status.frame_done, status.capture_done);
	if (dev->capture_mode == V4L2_MODE_IMAGE) {
		if (dev->is_isp_used)
			bsp_isp_irq_disable(FINISH_INT_EN);
		else
			bsp_csi_int_disable(dev->csi_sel, current_ch, CSI_INT_CAPTURE_DONE);
		vfe_print("ch%d capture image mode!\n", current_ch);
		buf = list_entry(dma_q->active.next, struct vfe_buffer, list);
		list_del(&buf->list);
		if (dev->special_active == 1) {
			list_add_tail(&buf->list, &done->active);
			need_callback = 1;
		} else {
			vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
		}
		goto unlock;
	} else {
		if (dev->is_isp_used)
			bsp_isp_irq_disable(FINISH_INT_EN);
		else
			bsp_csi_int_disable(dev->csi_sel, current_ch, CSI_INT_FRAME_DONE);
		if (dev->first_flag[current_ch] == 0) {
			dev->first_flag[current_ch]++;
			vfe_print("ch%d capture video mode!\n", current_ch);
			goto set_isp_stat_addr;
		}
		if (dev->first_flag[current_ch] == 1) {
			dev->first_flag[current_ch]++;
			vfe_print("ch%d capture video first frame done!\n", current_ch);
		}

		/* video buffer handle: */
		if ((&dma_q->active) == dma_q->active.next->next->next) {
			vfe_warn("Only two buffer left for csi ch%d\n", current_ch);
			dev->first_flag[current_ch] = 0;
			goto unlock;
		}
		buf = list_entry(dma_q->active.next, struct vfe_buffer, list);

		/* Nobody is waiting on this buffer*/
		if (!dev->special_active) {
			if (!waitqueue_active(&buf->vb.vb2_buf.vb2_queue->done_wq)) {
				vfe_warn("Nobody is waiting on buf = 0x%p, ch is %d\n", buf, current_ch);
			}
		}
		list_del(&buf->list);
		buf->vb.vb2_buf.timestamp = ktime_get_ns();
	/* buf->vb.image_quality = dev->isp_3a_result_pt->image_quality.dwval; */

		if (dev->special_active == 1) {
			list_add_tail(&buf->list, &done->active);
			need_callback = 1;
		} else {
			vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
		}
		/* isp_stat_handle: */

		if (dev->is_isp_used && dev->is_bayer_raw) {
			list_for_each_entry(stat_buf_pt, &isp_stat_bq->locked, queue) {
				if (stat_buf_pt->isp_stat_buf.buf_status == BUF_LOCKED) {
					vfe_dbg(3, "find isp stat buf locked!\n");
					vfe_dbg(3, "isp_stat_bq->locked = %p\n", &isp_stat_bq->locked);
					vfe_dbg(3, "isp_stat_bq->locked.next = %p\n", isp_stat_bq->locked.next);
					vfe_dbg(3, "isp_stat_bq->isp_stat[%d].queue = %p\n", stat_buf_pt->id, &isp_stat_bq->isp_stat[stat_buf_pt->id].queue);
					vfe_dbg(3, "isp_stat_bq->isp_stat[%d].queue.prev = %p\n", stat_buf_pt->id, isp_stat_bq->isp_stat[stat_buf_pt->id].queue.prev);
					vfe_dbg(3, "isp_stat_bq->isp_stat[%d].queue.next = %p\n", stat_buf_pt->id, isp_stat_bq->isp_stat[stat_buf_pt->id].queue.next);
					goto set_next_output_addr;
				}
			}
			for (i = 0; i < MAX_ISP_STAT_BUF; i++) {
				stat_buf_pt = &isp_stat_bq->isp_stat[i];
				if (stat_buf_pt->isp_stat_buf.buf_status == BUF_IDLE) {
					vfe_dbg(3, "find isp stat buf idle!\n");
					list_move_tail(&stat_buf_pt->queue, &isp_stat_bq->active);
					stat_buf_pt->isp_stat_buf.buf_status = BUF_ACTIVE;
				}
			}

			vfe_dbg(3, "before list empty isp_stat_bq->active = %p\n", &isp_stat_bq->active);
			vfe_dbg(3, "before list empty isp_stat_bq->active.prev = %p\n", isp_stat_bq->active.prev);
			vfe_dbg(3, "before list empty isp_stat_bq->active.next = %p\n", isp_stat_bq->active.next);

			/* judge if the isp stat queue has been written to the last */
			if (list_empty(&isp_stat_bq->active)) {
				vfe_err("No active isp stat queue to serve\n");
				goto set_next_output_addr;
			}
			vfe_dbg(3, "after list empty isp_stat_bq->active = %p\n", &isp_stat_bq->active);
			vfe_dbg(3, "after list empty isp_stat_bq->active.prev = %p\n", isp_stat_bq->active.prev);
			vfe_dbg(3, "after list empty isp_stat_bq->active.next = %p\n", isp_stat_bq->active.next);

			/*
			delete the ready buffer from the actvie queue
			add the ready buffer to the locked queue
			stat_buf_pt = list_first_entry(&isp_stat_bq->active, struct vfe_isp_stat_buf, queue);
			*/
			stat_buf_pt = list_entry(isp_stat_bq->active.next, struct vfe_isp_stat_buf, queue);

			list_move_tail(&stat_buf_pt->queue, &isp_stat_bq->locked);
			stat_buf_pt->isp_stat_buf.buf_status = BUF_LOCKED;
			dev->isp_gen_set_pt->stat.stat_buf_whole = &isp_stat_bq->isp_stat[stat_buf_pt->id].isp_stat_buf;
			vfe_isp_stat_parse(dev->isp_gen_set_pt);
			isp_stat_bq->isp_stat[stat_buf_pt->id].isp_stat_buf.frame_number++;

			if ((&isp_stat_bq->active) == isp_stat_bq->active.next->next) {
				vfe_warn("No more isp stat free frame on next time\n");
				goto set_next_output_addr;
			}
		}
	}

set_isp_stat_addr:
	if (dev->is_isp_used && dev->is_bayer_raw) {
		/* stat_buf_pt = list_entry(isp_stat_bq->active.next->next, struct vfe_isp_stat_buf, queue); */
		stat_buf_pt = list_entry(isp_stat_bq->active.next, struct vfe_isp_stat_buf, queue);
		bsp_isp_set_statistics_addr((unsigned long)(stat_buf_pt->dma_addr));
	}
set_next_output_addr:
	if (list_empty(&dma_q->active) || dma_q->active.next->next == (&dma_q->active)) {
		vfe_print("No active queue to serve\n");
		goto unlock;
	}
	buf = list_entry(dma_q->active.next->next, struct vfe_buffer, list);
	vfe_set_addr(dev, buf, current_ch);

unlock:
#if defined(CH_OUTPUT_IN_DIFFERENT_VIDEO)
	bsp_csi_int_clear_status(dev->csi_sel, current_ch, CSI_INT_FRAME_DONE);
	bsp_csi_int_clear_status(dev->csi_sel, current_ch, CSI_INT_CAPTURE_DONE);
	if ((dev->capture_mode == V4L2_MODE_VIDEO) ||
	    (dev->capture_mode == V4L2_MODE_PREVIEW))
		bsp_csi_int_enable(dev->csi_sel, current_ch, CSI_INT_FRAME_DONE);
#endif
	spin_unlock_irqrestore(&dev->slock, flags);

	if (dev->special_active && need_callback && dev->vfe_buffer_process)
		dev->vfe_buffer_process(dev->id);

	if (((dev->capture_mode == V4L2_MODE_VIDEO) || (dev->capture_mode == V4L2_MODE_PREVIEW))
		&& dev->is_isp_used && bsp_isp_get_irq_status(FINISH_INT_EN)) {
		/* if(bsp_isp_get_para_ready()) */
		vfe_dbg(3, "call tasklet schedule!\n");
		bsp_isp_clr_para_ready();
		schedule_work(&dev->isp_isr_bh_task);
		bsp_isp_set_para_ready();
	}
#if !defined(CH_OUTPUT_IN_DIFFERENT_VIDEO)
	if (dev->is_isp_used) {
		bsp_isp_clr_irq_status(FINISH_INT_EN);
		bsp_isp_irq_enable(FINISH_INT_EN);
	} else {
		bsp_csi_int_clear_status(dev->csi_sel, dev->cur_ch, CSI_INT_FRAME_DONE);
		bsp_csi_int_clear_status(dev->csi_sel, dev->cur_ch, CSI_INT_CAPTURE_DONE);
		if ((dev->capture_mode == V4L2_MODE_VIDEO) ||
		    (dev->capture_mode == V4L2_MODE_PREVIEW))
			bsp_csi_int_enable(dev->csi_sel, dev->cur_ch, CSI_INT_FRAME_DONE);
	}
#endif
	return IRQ_HANDLED;
}

/*
 * Videobuf operations
 */
static int queue_setup(struct vb2_queue *vq,
				unsigned int *nbuffers, unsigned int *nplanes,
				unsigned int sizes[], struct device *alloc_devs[])
{
	struct vfe_dev *dev = vb2_get_drv_priv(vq);
	unsigned int size;
	int buf_max_flag = 0;

	vfe_dbg(1, "queue_setup\n");

	size = dev->buf_byte_size;

	if (size == 0)
		return -EINVAL;

	if (*nbuffers == 0)
		*nbuffers = 8;

	while (size * *nbuffers > MAX_FRAME_MEM) {
		(*nbuffers)--;
		buf_max_flag = 1;
		if (*nbuffers == 0)
			vfe_err("one buffer size larger than max frame memory! buffer count = %d\n,", *nbuffers);
	}

	if (buf_max_flag == 0) {
		if (dev->capture_mode == V4L2_MODE_IMAGE) {
			if (*nbuffers != 1) {
				*nbuffers = 1;
				vfe_err("buffer count is set to 1 in image capture mode\n");
			}
		} else {
			if (*nbuffers < 3) {
				*nbuffers = 3;
				vfe_err("buffer count is invalid, set to 3 in video capture\n");
			}
		}
	}

	*nplanes = 1;
	sizes[0] = size;
	alloc_devs[0] = dev->allocate_dev[dev->cur_ch];

	vfe_print("%s, buffer count=%d, size=%d\n", __func__, *nbuffers, size);

	return 0;
}

static int buffer_prepare(struct vb2_buffer *vb)
{
	struct vfe_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
	struct vb2_v4l2_buffer *vvb = container_of(vb, struct vb2_v4l2_buffer, vb2_buf);
	struct vfe_buffer *buf = container_of(vvb, struct vfe_buffer, vb);
	unsigned long size;

	vfe_dbg(1, "buffer_prepare\n");

	if (dev->width < MIN_WIDTH || dev->width  > MAX_WIDTH ||
			dev->height < MIN_HEIGHT || dev->height > MAX_HEIGHT)
		return -EINVAL;

	size = dev->buf_byte_size;

	if (vb2_plane_size(vb, 0) < size) {
		vfe_err("%s data will not fit into plane (%lu < %lu)\n",
					__func__, vb2_plane_size(vb, 0), size);
		return -EINVAL;
	}

	vb2_set_plane_payload(&buf->vb.vb2_buf, 0, size);

	vb->planes[0].m.offset = vb2_dma_contig_plane_dma_addr(vb, 0);

	return 0;
}

static void buffer_queue(struct vb2_buffer *vb)
{
	struct vfe_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
	struct vb2_v4l2_buffer *vvb = container_of(vb, struct vb2_v4l2_buffer, vb2_buf);
	struct vfe_buffer *buf = container_of(vvb, struct vfe_buffer, vb);
	struct vfe_dmaqueue *vidq = &dev->vidq[dev->cur_ch];
	unsigned long flags = 0;

	vfe_dbg(1, "ch%d buffer_queue\n", dev->cur_ch);
	spin_lock_irqsave(&dev->slock, flags);
	list_add_tail(&buf->list, &vidq->active);
	spin_unlock_irqrestore(&dev->slock, flags);
}

static int start_streaming(struct vb2_queue *vq, unsigned int count)
{
	struct vfe_dev *dev = vb2_get_drv_priv(vq);

	vfe_dbg(1, "%s\n", __func__);
	if (dev->cur_ch == 0)
		vfe_start_generating(dev);

	return 0;
}

/* abort streaming and wait for last buffer */
static void stop_streaming(struct vb2_queue *vq)
{
	struct vfe_dev *dev = vb2_get_drv_priv(vq);
	struct vfe_dmaqueue *dma_q = &dev->vidq[dev->cur_ch];
	unsigned long flags = 0;

	vfe_dbg(1, "%s\n", __func__);

	if (dev->cur_ch == 0)
		vfe_stop_generating(dev);

	spin_lock_irqsave(&dev->slock, flags);
	/* Release all active buffers */
	while (!list_empty(&dma_q->active)) {
		struct vfe_buffer *buf;

		buf = list_entry(dma_q->active.next, struct vfe_buffer, list);
		list_del(&buf->list);
		vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
		vfe_dbg(2, "[%p/%d] done\n", buf, buf->vb.vb2_buf.index);
	}
	spin_unlock_irqrestore(&dev->slock, flags);
}

static void vfe_lock(struct vb2_queue *vq)
{
	struct vfe_dev *dev = vb2_get_drv_priv(vq);

	mutex_lock(&dev->buf_lock);
}

static void vfe_unlock(struct vb2_queue *vq)
{
	struct vfe_dev *dev = vb2_get_drv_priv(vq);

	mutex_unlock(&dev->buf_lock);
}

static const struct vb2_ops vfe_video_qops = {
	.queue_setup      = queue_setup,
	.buf_prepare      = buffer_prepare,
	.buf_queue        = buffer_queue,
	.start_streaming  = start_streaming,
	.stop_streaming   = stop_streaming,
	.wait_prepare     = vfe_unlock,
	.wait_finish      = vfe_lock,
};

/*
 * IOCTL vidioc handling
 */
static int vidioc_querycap(struct file *file, void  *priv,
	  struct v4l2_capability *cap)
{
	struct vfe_dev *dev = video_drvdata(file);

	strcpy(cap->driver, "sunxi-vfe");
	strcpy(cap->card, "sunxi-vfe");
	strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info));

	cap->version = VFE_VERSION;
	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | \
			V4L2_CAP_READWRITE | V4L2_CAP_DEVICE_CAPS;

	cap->device_caps |= V4L2_CAP_EXT_PIX_FORMAT;

	return 0;
}

static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
	  struct v4l2_fmtdesc *f)
{
	struct vfe_fmt *fmt;

	vfe_dbg(0, "vidioc_enum_fmt_vid_cap\n");

	if (f->index > ARRAY_SIZE(formats) - 1)
		return -EINVAL;

	fmt = &formats[f->index];

	strlcpy(f->description, fmt->name, sizeof(f->description));
	f->pixelformat = fmt->fourcc;

	return 0;
}


static int vidioc_enum_framesizes(struct file *file, void *fh,
	  struct v4l2_frmsizeenum *fsize)
{
	struct vfe_dev *dev = video_drvdata(file);
	struct v4l2_subdev_frame_size_enum fse;
	int ret;

	vfe_dbg(0, "vidioc_enum_framesizes\n");

	fse.index = fsize->index;
	if (dev == NULL || dev->sd->ops->pad->enum_frame_size == NULL)
		return -EINVAL;

	ret = v4l2_subdev_call(dev->sd, pad, enum_frame_size, NULL, &fse);
	if (ret < 0)
		return -1;
	fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
	fsize->stepwise.max_width = fse.max_width;
	fsize->stepwise.max_height = fse.max_height;
	fsize->stepwise.min_width = fse.min_width;
	fsize->stepwise.min_height = fse.min_height;

	return ret;
}

static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
							struct v4l2_format *f)
{
	struct vfe_dev *dev = video_drvdata(file);

	f->fmt.pix.width        = dev->width;
	f->fmt.pix.height       = dev->height;
	f->fmt.pix.field	= dev->fmt.field;
	f->fmt.pix.pixelformat  = dev->fmt.bus_pix_code;

	return 0;
}

static u32 *try_fmt_from_sensor(struct vfe_dev *dev, char *bus_name,
			char *pix_name, struct v4l2_subdev_format *fmat)
{
//	struct vfe_fmt_code *vfe_formats, *def_fmt = NULL;
	int ret = 0;
//	u32 *mbus_code;
//	unsigned int i;

	ret = dev->sd->ops->pad->get_fmt(dev->sd, NULL, fmat);
	if (ret < 0)
		vfe_err("get_fmt from sensor error!\n");

	vfe_print("get mbus_code from sensor 0x%x!\n", fmat->format.code);
	return &fmat->format.code;

#if 0
	for (i = 0; i < ARRAY_SIZE(vfe_fmt_code); i++) {
		vfe_formats = &vfe_fmt_code[i];

		if (bus_name == vfe_formats->bus_name && pix_name == vfe_formats->pix_name) {
			def_fmt = vfe_formats;
			mbus_code = vfe_formats->mbus_code;
			for (i = 0; i < def_fmt->size; ++i) {
				fmat->format.code = mbus_code[i];
				ret = v4l2_subdev_call(dev->sd, pad, get_fmt, NULL, fmat);
				if (ret >= 0) {
					vfe_dbg(0, "try %s bus ok when pix fmt is %s!\n", bus_name, pix_name);

					return &fmat->format.code;
				}

			}

		}
	}

	vfe_err("try %s bus error when pix fmt is %s!\n", bus_name, pix_name);

	return NULL;
#endif
}

static u32 *try_fmt_internal(struct vfe_dev *dev, struct v4l2_format *f)
{
	enum pixel_fmt pix_fmt;
	enum pixel_fmt_type pix_fmt_type;
	struct v4l2_subdev_format fmat;
	struct v4l2_mbus_framefmt *ccm_fmt = &fmat.format;
	u32 *bus_pix_code = NULL;

	vfe_dbg(0, "try_fmt_internal\n");

	/*judge the resolution*/
	if (f->fmt.pix.width > MAX_WIDTH || f->fmt.pix.height > MAX_HEIGHT) {
		vfe_err("size is too large,automatically set to maximum!\n");
		f->fmt.pix.width = MAX_WIDTH;
		f->fmt.pix.height = MAX_HEIGHT;
	}

	pix_fmt = pix_fmt_v4l2_to_common(f->fmt.pix.pixelformat);
	pix_fmt_type = find_pixel_fmt_type(pix_fmt);

	ccm_fmt->width = f->fmt.pix.width;
	ccm_fmt->height = f->fmt.pix.height;
	ccm_fmt->field = f->fmt.pix.field;
	/* find the expect bus format via frame format list */
	if (pix_fmt_type == YUV422_PL || pix_fmt_type == YUV422_SPL || \
			pix_fmt_type == YUV420_PL || pix_fmt_type == YUV420_SPL
#ifdef CONFIG_ARCH_SUN3IW1P1
      || pix_fmt_type == YUV420_MB
#endif
	  ) {
		if (dev->is_isp_used && dev->is_bayer_raw) {
			bus_pix_code = try_fmt_from_sensor(dev, "bayer", "yuv422/yuv420", &fmat);
			if (bus_pix_code == NULL) {
				bus_pix_code = try_fmt_from_sensor(dev, "yuv422", "yuv422/yuv420", &fmat);
				if (bus_pix_code == NULL) {
					if (pix_fmt_type == YUV420_PL || pix_fmt_type == YUV420_SPL) {
						bus_pix_code = try_fmt_from_sensor(dev, "yuv420", "yuv422/yuv420", &fmat);
					} else {
						return NULL;
					}
				}
			}
		} else {
			bus_pix_code = try_fmt_from_sensor(dev, "yuv422", "yuv422/yuv420", &fmat);
			if (bus_pix_code == NULL) {
				if (pix_fmt_type == YUV420_PL || pix_fmt_type == YUV420_SPL) {

				} else {
					return NULL;
				}
			}
		}
	} else if (pix_fmt_type == YUV422_INTLVD) {
		bus_pix_code = try_fmt_from_sensor(dev, "yuv422", "yuv422/yuv420", &fmat);
	} else if (pix_fmt_type == BAYER_RGB) {
		bus_pix_code = try_fmt_from_sensor(dev, "bayer", "yuv422/yuv420", &fmat);
	} else if (pix_fmt_type == RGB565) {
		bus_pix_code = try_fmt_from_sensor(dev, "rgb565", "rgb565", &fmat);
	} else if (pix_fmt_type == RGB888 || pix_fmt_type == PRGB888) {
		bus_pix_code = try_fmt_from_sensor(dev, "rgb888", "rgb888/prgb888", &fmat);
	} else {
		return NULL;
	}

	if (bus_pix_code == NULL)
		return NULL;

	f->fmt.pix.width = ccm_fmt->width;
	f->fmt.pix.height = ccm_fmt->height;

	vfe_dbg(0, "bus pixel code = %x at %s\n", *bus_pix_code, __func__);
	vfe_dbg(0, "pix->width = %d at %s\n", f->fmt.pix.width, __func__);
	vfe_dbg(0, "pix->height = %d at %s\n", f->fmt.pix.height, __func__);

	return (u32 *)bus_pix_code;
}

static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
							struct v4l2_format *f)
{
	struct vfe_dev *dev = video_drvdata(file);
	u32 bus_pix_code;

	vfe_dbg(0, "vidioc_try_fmt_vid_cap\n");

	bus_pix_code = (u32)try_fmt_internal(dev, f);
	if (!bus_pix_code) {
		vfe_err("pixel format (0x%08x) width %d height %d invalid at %s.\n", \
			f->fmt.pix.pixelformat, f->fmt.pix.width, f->fmt.pix.height, __func__);
		return -EINVAL;
	}

	return 0;
}

static int s_fmt_internal(struct vfe_dev *dev, void *priv,
		struct v4l2_format *f)
{
	struct v4l2_subdev_format fmat;
	struct v4l2_mbus_framefmt *ccm_fmt = &fmat.format;
	struct v4l2_mbus_config mbus_cfg;
	u32 bus_pix_code;
	struct sensor_win_size win_cfg;
	struct main_channel_cfg main_cfg;
	struct v4l2_subdev_format csi_fmt;
	struct v4l2_subdev_format mipi_fmt;
	int ret;

	vfe_dbg(0, "vidioc_s_fmt_vid_cap\n");

	if (vfe_is_generating(dev)) {
		vfe_err("%s device busy\n", __func__);
		return -EBUSY;
	}

	bus_pix_code = (u32)try_fmt_internal(dev, f);
	if (!bus_pix_code) {
		vfe_err("pixel format (0x%08x) width %d height %d invalid at %s.\n", \
			f->fmt.pix.pixelformat, f->fmt.pix.width, f->fmt.pix.height, __func__);
		ret = -EINVAL;
		goto out;
	}
	vfe_dbg(0, "bus pixel code = %x at %s\n", bus_pix_code, __func__);
	vfe_dbg(0, "pix->width = %d at %s\n", f->fmt.pix.width, __func__);
	vfe_dbg(0, "pix->height = %d at %s\n", f->fmt.pix.height, __func__);

	/* get current win configs */
	memset(&win_cfg, 0, sizeof(struct sensor_win_size));
	ret = v4l2_subdev_call(dev->sd, core, ioctl, GET_CURRENT_WIN_CFG, &win_cfg);

	ret = v4l2_subdev_call(dev->sd, pad, get_mbus_config, 0, &mbus_cfg);
	if (ret < 0) {
		vfe_err("v4l2 sub device sensor g_mbus_config error!\n");
		goto out;
	}

	ret = dev->csi_sd->ops->pad->set_mbus_config(dev->csi_sd, 0, &mbus_cfg);
//	ret = v4l2_subdev_call(dev->csi_sd, pad, set_mbus_config, 0, &mbus_cfg);
	if (ret < 0) {
		vfe_err("v4l2 sub device csi s_mbus_config error!\n");
		goto out;
	}

	if (mbus_cfg.type == V4L2_MBUS_CSI2_DPHY) {
		ret = v4l2_subdev_call(dev->mipi_sd, pad, set_mbus_config, 0, &mbus_cfg);
		if (ret < 0) {
			vfe_err("v4l2 sub device mipi s_mbus_config error!\n");
			goto out;
		}

		mipi_fmt.reserved[0] = win_cfg.mipi_bps;
		mipi_fmt.format.code = bus_pix_code;
		mipi_fmt.format.field = f->fmt.pix.field;

		ret = v4l2_subdev_call(dev->mipi_sd, pad, set_fmt, NULL, &mipi_fmt);
		if (ret < 0) {
			vfe_err("v4l2 sub device mipi set_fmt error!\n");
			goto out;
		}
		usleep_range(1000, 2000);
		v4l2_subdev_call(dev->mipi_sd, core, s_power, 0);
		bsp_mipi_csi_dphy_enable(dev->mipi_sel);
		v4l2_subdev_call(dev->mipi_sd, core, s_power, 1);
		usleep_range(10000, 12000);
	}

	/* init device */
	ccm_fmt->code = bus_pix_code;
	ccm_fmt->width = f->fmt.pix.width;
	ccm_fmt->height = f->fmt.pix.height;
	ccm_fmt->field = f->fmt.pix.field;

	if (dev->capture_mode == V4L2_MODE_IMAGE)
		sunxi_flash_check_to_start(dev->flash_sd, SW_CTRL_FLASH_ON);
	else
		sunxi_flash_stop(dev->flash_sd);

//	ret = v4l2_subdev_call(dev->sd, pad, set_fmt, NULL, &fmat);
	ret = dev->sd->ops->pad->set_fmt(dev->sd, 0, &fmat);
	if (ret < 0) {
		vfe_err("v4l2 sub device sensor s_mbus_fmt error!\n");
		goto out;
	}

	/*
	prepare the vfe bsp parameter
	assuming using single channel
	*/
	csi_fmt.format = fmat.format;
	csi_fmt.format.reserved[0] = win_cfg.hoffset;
	csi_fmt.format.reserved[1] = win_cfg.voffset;
	csi_fmt.reserved[0] = f->fmt.pix.pixelformat;

//	ret = v4l2_subdev_call(dev->csi_sd, pad, set_fmt, NULL, &csi_fmt);
	ret = dev->csi_sd->ops->pad->set_fmt(dev->csi_sd, 0, &csi_fmt);
	if (ret < 0) {
		vfe_err("v4l2 sub device csi set_fmt error!\n");
		goto out;
	}

	dev->fmt.bus_pix_code = bus_pix_code;
	dev->fmt.field = ccm_fmt->field;

	if (dev->is_isp_used) {
		main_cfg.pix = f->fmt.pix;
		main_cfg.win_cfg = win_cfg;
		main_cfg.bus_code = find_bus_type((enum bus_pixelcode)(bus_pix_code));
		ret = v4l2_subdev_call(dev->isp_sd, core, ioctl, VIDIOC_SUNXI_ISP_MAIN_CH_CFG, &main_cfg);
		if (ret < 0)
			vfe_err("vidioc_set_main_channel error! ret = %d\n", ret);
		dev->isp_gen_set_pt->double_ch_flag = 0;
		dev->buf_byte_size = main_cfg.pix.sizeimage;
		vfe_print("dev->buf_byte_size = %d, double_ch_flag = %d\n", dev->buf_byte_size, dev->isp_gen_set_pt->double_ch_flag);
	} else {
		v4l2_subdev_call(dev->csi_sd, core, ioctl, VIDIOC_SUNXI_CSI_GET_FRM_SIZE, &dev->buf_byte_size);
		vfe_print("dev->buf_byte_size = %d\n", dev->buf_byte_size);
	}
	dev->thumb_width  = 0;
	dev->thumb_height = 0;
	dev->width  = ccm_fmt->width;
	dev->height = ccm_fmt->height;

	dev->mbus_type = mbus_cfg.type;
	if (dev->is_isp_used == 1) {
		vfe_dbg(0, "isp_module_init start!\n");
		if (dev->is_bayer_raw == 1) {
			if (0 == win_cfg.width_input || 0 == win_cfg.height_input) {
				win_cfg.width_input = win_cfg.width;
				win_cfg.height_input = win_cfg.height;
				}
			dev->isp_gen_set_pt->stat.pic_size.width = win_cfg.width_input;
			dev->isp_gen_set_pt->stat.pic_size.height = win_cfg.height_input;

			dev->isp_gen_set_pt->stat.hoffset = win_cfg.hoffset;
			dev->isp_gen_set_pt->stat.voffset = win_cfg.voffset;
			dev->isp_gen_set_pt->stat.hts = win_cfg.hts;
			dev->isp_gen_set_pt->stat.vts = win_cfg.vts;
			dev->isp_gen_set_pt->stat.pclk = win_cfg.pclk;
			dev->isp_gen_set_pt->stat.fps_fixed = win_cfg.fps_fixed;
			dev->isp_gen_set_pt->stat.bin_factor = win_cfg.bin_factor;
			dev->isp_gen_set_pt->stat.intg_min = win_cfg.intg_min;
			dev->isp_gen_set_pt->stat.intg_max = win_cfg.intg_max;
			dev->isp_gen_set_pt->stat.gain_min = win_cfg.gain_min;
			dev->isp_gen_set_pt->stat.gain_max = win_cfg.gain_max;

			if (dev->capture_mode == V4L2_MODE_IMAGE)
				dev->isp_gen_set_pt->sensor_mod = CAPTURE_MODE;
			else if (dev->capture_mode == V4L2_MODE_VIDEO)
				dev->isp_gen_set_pt->sensor_mod = VIDEO_MODE;
			else
				dev->isp_gen_set_pt->sensor_mod = PREVIEW_MODE;

			isp_module_init(dev->isp_gen_set_pt, dev->isp_3a_result_pt);
			dev->ctrl_para.prev_exp_line = 0;
			dev->ctrl_para.prev_ana_gain = 1;
			if (set_sensor_shutter_and_gain(dev) != 0) {
				set_sensor_shutter(dev, dev->isp_3a_result_pt->exp_line_num);
				set_sensor_gain(dev, dev->isp_3a_result_pt->exp_analog_gain);
			}
			usleep_range(50000, 60000);
		} else
			isp_module_init(dev->isp_gen_set_pt, NULL);

		vfe_dbg(0, "isp_module_init end!\n");
	}

	ret = 0;
out:
	return ret;
}

static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
			struct v4l2_format *f)
{
	struct vfe_dev *dev = video_drvdata(file);
	struct video_device *vdev = video_devdata(file);

	dev->cur_ch = (vdev->num - VID_N_OFF) < 0 ? 0 : (vdev->num - VID_N_OFF);
	if (dev->cur_ch > 0)
		return 0;

	return s_fmt_internal(dev, priv, f);
}

static int vidioc_reqbufs(struct file *file, void *priv,
				struct v4l2_requestbuffers *p)
{
	struct vfe_dev *dev = video_drvdata(file);
	struct video_device *vdev = video_devdata(file);

	dev->cur_ch = (vdev->num - VID_N_OFF) < 0 ? 0 : (vdev->num - VID_N_OFF);

	vfe_dbg(0, "vidioc_reqbufs\n");

	return vb2_reqbufs(&dev->vb_vidq[dev->cur_ch], p);
}

static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
{
	struct vfe_dev *dev = video_drvdata(file);
	struct video_device *vdev = video_devdata(file);

	dev->cur_ch = (vdev->num - VID_N_OFF) < 0 ? 0 : (vdev->num - VID_N_OFF);

	return vb2_querybuf(&dev->vb_vidq[dev->cur_ch], p);
}

static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
{
	struct vfe_dev *dev = video_drvdata(file);
	struct video_device *vdev = video_devdata(file);

	dev->cur_ch = (vdev->num - VID_N_OFF) < 0 ? 0 : (vdev->num - VID_N_OFF);

	return vb2_qbuf(&dev->vb_vidq[dev->cur_ch], dev->v4l2_dev.mdev, p);
}

static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
{
	struct vfe_dev *dev = video_drvdata(file);
	struct video_device *vdev = video_devdata(file);

	dev->cur_ch = (vdev->num - VID_N_OFF) < 0 ? 0 : (vdev->num - VID_N_OFF);

	vfe_dbg(2, "vidioc dqbuf\n");
	return vb2_dqbuf(&dev->vb_vidq[dev->cur_ch], p, file->f_flags & O_NONBLOCK);
}

#define CSI_PIN1_REG 0xf1c20890
#define CSI_PIN2_REG 0xf1c20894


static int __vfe_streamon(struct vfe_dev *dev, void *priv, enum v4l2_buf_type i)
{
	struct vfe_dmaqueue *dma_q = &dev->vidq[dev->cur_ch];
	struct vfe_isp_stat_buf_queue *isp_stat_bq = &dev->isp_stat_bq;
	struct vfe_buffer *buf = NULL;
	struct vfe_isp_stat_buf *stat_buf_pt;
	int ret = 0, j;

#ifdef CONFIG_ARCH_SUN3IW1P1
	int val;

	writel(0x22222222, CSI_PIN1_REG);

	val = readl(CSI_PIN2_REG) & 0xffff0000;
	val |= 0x2222;
	writel(val, CSI_PIN2_REG);
#endif
	mutex_lock(&dev->stream_lock);
	vfe_dbg(0, "video stream on\n");
	if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
		ret = -EINVAL;
		goto streamon_unlock;
	}
	if (dev->cur_ch == 0) {
		if (vfe_is_generating(dev)) {
			vfe_err("stream has been already on\n");
			ret = -1;
			goto streamon_unlock;
		}
		bsp_csi_enable(dev->csi_sel);
		bsp_csi_disable(dev->csi_sel);
		bsp_csi_enable(dev->csi_sel);
	}

	/* initial for sensor */
	v4l2_subdev_call(dev->sd, video, s_stream, 1);

	if (dev->is_isp_used) {
		v4l2_subdev_call(dev->isp_sd, video, s_stream, 1);
		bsp_isp_enable();
	}
	if (dev->is_isp_used && dev->is_bayer_raw) {
		/* initial for isp statistic buffer queue */
		INIT_LIST_HEAD(&isp_stat_bq->active);
		INIT_LIST_HEAD(&isp_stat_bq->locked);
		for (j = 0; j < MAX_ISP_STAT_BUF; j++) {
			isp_stat_bq->isp_stat[j].isp_stat_buf.buf_status = BUF_ACTIVE;
			list_add_tail(&isp_stat_bq->isp_stat[j].queue, &isp_stat_bq->active);
		}
	}
	if (dev->special_active == 1) {
		dma_q = &dev->vidq_special;
		vfe_start_generating(dev);
	} else {
		ret = vb2_streamon(&dev->vb_vidq[dev->cur_ch], i);
		if (ret)
			goto streamon_unlock;
	}
	if (!list_empty(&dma_q->active)) {
		buf = list_entry(dma_q->active.next, struct vfe_buffer, list);
	} else {
		vfe_err("stream on, but no buffer now.\n");
		goto streamon_unlock;
	}
	vfe_set_addr(dev, buf, dev->cur_ch);
#if defined(CH_OUTPUT_IN_DIFFERENT_VIDEO)
	if ((dev->cur_ch == 0) && (dev->id == 0)) {
		int ch = 0;
		dma_addr_t dma_addr;

		for (ch = 1; ch < MAX_CH_NUM; ch++) {
			dev->buf_ext[ch].size = dev->buf_byte_size;
			ret = os_mem_alloc(&dev->pdev->dev, &dev->buf_ext[ch]);
			if (ret)
				goto streamon_unlock;

			dma_addr = (dma_addr_t)dev->buf_ext[ch].dma_addr;
			bsp_csi_set_ch_addr(dev->csi_sel, ch, dma_addr);
		}
	}
#endif
	if (dev->is_isp_used && dev->is_bayer_raw) {
		stat_buf_pt = list_entry(isp_stat_bq->active.next, struct vfe_isp_stat_buf, queue);
		if (stat_buf_pt == NULL) {
			vfe_err("stat_buf_pt =null");
		} else {
			bsp_isp_set_statistics_addr((unsigned long)(stat_buf_pt->dma_addr));
		}
	}

	if (dev->is_isp_used) {
		bsp_isp_set_para_ready();
		bsp_isp_clr_irq_status(ISP_IRQ_EN_ALL);
		bsp_isp_irq_enable(FINISH_INT_EN | SRC0_FIFO_INT_EN);
		if (dev->is_isp_used && dev->is_bayer_raw)
			bsp_csi_int_enable(dev->csi_sel, dev->cur_ch, CSI_INT_VSYNC_TRIG);
	} else {
		bsp_csi_int_clear_status(dev->csi_sel, dev->cur_ch, CSI_INT_ALL);
		bsp_csi_int_enable(dev->csi_sel, dev->cur_ch, CSI_INT_CAPTURE_DONE | \
						      CSI_INT_FRAME_DONE | \
						      CSI_INT_BUF_0_OVERFLOW | \
						      CSI_INT_BUF_1_OVERFLOW | \
						      CSI_INT_BUF_2_OVERFLOW | \
						      CSI_INT_HBLANK_OVERFLOW);
	}
#if defined(CONFIG_ARCH_SUN8IW8P1)
	if (dev->mbus_type == V4L2_MBUS_CSI2)
		bsp_mipi_csi_protocol_enable(dev->mipi_sel);

	usleep_range(10000, 11000);

	if (dev->capture_mode == V4L2_MODE_IMAGE) {
		if (dev->is_isp_used)
			bsp_isp_image_capture_start();
	} else {
		if (dev->is_isp_used)
			bsp_isp_video_capture_start();
	}
	v4l2_subdev_call(dev->csi_sd, video, s_stream, 1);
#else
	if (dev->capture_mode == V4L2_MODE_IMAGE) {
		if (dev->is_isp_used)
			bsp_isp_image_capture_start();
	} else {
		if (dev->is_isp_used)
			bsp_isp_video_capture_start();
	}
	if (dev->cur_ch == 0)
		v4l2_subdev_call(dev->csi_sd, video, s_stream, 1);

	if (dev->mbus_type == V4L2_MBUS_CSI2_DPHY)
		bsp_mipi_csi_protocol_enable(dev->mipi_sel);
#endif
streamon_unlock:
	mutex_unlock(&dev->stream_lock);

	return ret;
}

static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
{
	struct vfe_dev *dev = video_drvdata(file);
	struct video_device *vdev = video_devdata(file);

	dev->cur_ch = (vdev->num - VID_N_OFF) < 0 ? 0 : (vdev->num - VID_N_OFF);

	return __vfe_streamon(dev, priv, i);
}

static int __vfe_streamoff(struct vfe_dev *dev, void *priv, enum v4l2_buf_type i)
{
	struct vfe_dmaqueue *dma_q = &dev->vidq[dev->cur_ch];
	struct vfe_dmaqueue *donelist = NULL;
	struct vfe_buffer *buffer = NULL;
	unsigned long flags = 0;
	int ret = 0;

#ifdef CONFIG_ARCH_SUN3IW1P1
	u32 val = 0;
#endif

	mutex_lock(&dev->stream_lock);
	vfe_dbg(0, "video stream off\n");
	if (dev->cur_ch == 0) {
		if (!vfe_is_generating(dev)) {
			vfe_err("stream has been already off\n");
			ret = 0;
			goto streamoff_unlock;
		}
		isp_streamoff_torch_and_flash_close(dev);
	}

	if (dev->is_isp_used) {
		vfe_dbg(0, "disable isp int in streamoff\n");
		bsp_isp_irq_disable(ISP_IRQ_EN_ALL);
		bsp_isp_clr_irq_status(ISP_IRQ_EN_ALL);
	} else {
		vfe_dbg(0, "disable csi int in streamoff\n");
		bsp_csi_int_disable(dev->csi_sel, dev->cur_ch, CSI_INT_ALL);
		bsp_csi_int_clear_status(dev->csi_sel, dev->cur_ch, CSI_INT_ALL);
	}
	if (dev->cur_ch == 0)
		v4l2_subdev_call(dev->csi_sd, video, s_stream, 0);
	if (dev->capture_mode == V4L2_MODE_IMAGE) {
		if (dev->is_isp_used)
			bsp_isp_image_capture_stop();
		vfe_dbg(0, "dev->capture_mode = %d\n", dev->capture_mode);
	} else {
		if (dev->is_isp_used)
			bsp_isp_video_capture_stop();
		vfe_dbg(0, "dev->capture_mode = %d\n", dev->capture_mode);
	}
	if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
		ret = -EINVAL;
		goto streamoff_unlock;
	}
	if (dev->mbus_type == V4L2_MBUS_CSI2_DPHY)
		bsp_mipi_csi_protocol_disable(dev->mipi_sel);

	if (dev->special_active == 1) {
		dma_q = &dev->vidq_special;
		donelist = &dev->done_special;
		vfe_stop_generating(dev);
		spin_lock_irqsave(&dev->slock, flags);
		while (!list_empty(&dma_q->active)) {
			buffer = list_first_entry(&dma_q->active, struct vfe_buffer, list);
			list_del(&buffer->list);
			list_add(&buffer->list, &donelist->active);
		}
		spin_unlock_irqrestore(&dev->slock, flags);
	} else {
		ret = vb2_streamoff(&dev->vb_vidq[dev->cur_ch], i);
		if (ret != 0) {
			vfe_err("videobu_streamoff error!\n");
			goto streamoff_unlock;
		}
	}

#if defined(CH_OUTPUT_IN_DIFFERENT_VIDEO)
	if ((dev->cur_ch == 0) && (dev->id == 0)) {
		int ch = 0;

		for (ch = 1; ch < MAX_CH_NUM; ch++)
			os_mem_free(&dev->pdev->dev, &dev->buf_ext[ch]);
	}
#endif

	if (dev->is_isp_used)
		bsp_isp_disable();

	if (dev->cur_ch == 0)
		bsp_csi_disable(dev->csi_sel);
#ifdef CONFIG_ARCH_SUN3IW1P1
	writel(0x7777777, CSI_PIN1_REG);
	val = readl(CSI_PIN2_REG) & 0xffff0000;
	val |= 0x7777;
	writel(val, CSI_PIN2_REG);
#endif

streamoff_unlock:
	mutex_unlock(&dev->stream_lock);

	return ret;
}

static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
{
	struct vfe_dev *dev = video_drvdata(file);
	struct video_device *vdev = video_devdata(file);

	dev->cur_ch = (vdev->num - VID_N_OFF) < 0 ? 0 : (vdev->num - VID_N_OFF);

	return __vfe_streamoff(dev, priv, i);
}

static int vidioc_enum_input(struct file *file, void *priv,
	struct v4l2_input *inp)
{
	struct vfe_dev *dev = video_drvdata(file);

	if (inp->index > dev->dev_qty-1) {
		vfe_err("input index(%d) > dev->dev_qty(%d)-1 invalid!\n",
						inp->index, dev->dev_qty);
		return -EINVAL;
	}
	if (dev->device_valid_flag[inp->index] == 0) {
		vfe_err("input index(%d) > dev->dev_qty(%d)-1 invalid!, device_valid_flag[%d] = %d\n",
			inp->index, dev->dev_qty, inp->index, dev->device_valid_flag[inp->index]);
		return -EINVAL;
	}
	inp->type = V4L2_INPUT_TYPE_CAMERA;

	return 0;
}

static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
{
	struct vfe_dev *dev = video_drvdata(file);

	*i = dev->input;
	return 0;
}

static int vfe_ctrl_para_reset(struct vfe_dev *dev)
{
	dev->ctrl_para.gsensor_rot = 0;
	dev->ctrl_para.prev_exp_line = 16;
	dev->ctrl_para.prev_ana_gain = 16;
	dev->ctrl_para.prev_focus_pos = 50;

	return 0;
}

static int internal_s_input(struct vfe_dev *dev, unsigned int i)
{
	struct v4l2_control ctrl;
	struct sensor_item sensor_info;
	unsigned long core_clk;
	int ret;

	if (i > dev->dev_qty-1) {
		vfe_err("set input i(%d)>dev_qty(%d)-1 error!\n", i, dev->dev_qty);
		return -EINVAL;
	}

	if (i == dev->input)
		return 0;

	if (dev->input != -1) {
	/*Power down current device*/
		if (dev->sd_act != NULL)
			v4l2_subdev_call(dev->sd_act, core, ioctl, ACT_SOFT_PWDN, 0);

		ret = vfe_set_sensor_power_off(dev);
		if (ret < 0)
			goto altend;
	}
	vfe_dbg(0, "input_num = %d\n", i);

	dev->input = i;

	/* Alternate the device info and select target device*/
	update_ccm_info(dev, dev->ccm_cfg[i]);

	/* set vfe core clk rate for each sensor! */
	if (get_sensor_info(dev->ccm_cfg[i]->ccm, &sensor_info) == 0) {
		core_clk = sensor_info.core_clk_for_sensor;
	} else {
		core_clk = CSI_CORE_CLK_RATE;
	}
	v4l2_subdev_call(dev->csi_sd, core, ioctl, VIDIOC_SUNXI_CSI_SET_CORE_CLK, &core_clk);

	/* alternate isp setting */
	update_isp_setting(dev);
	if (dev->is_bayer_raw)
		isp_param_init(dev->isp_gen_set_pt);

	if (dev->flash_used == 1)
		sunxi_flash_info_init(dev->flash_sd);

	/* Initial target device */
	ret = vfe_set_sensor_power_on(dev);
#ifdef USE_SPECIFIC_CCI
	csi_cci_init_helper(dev->cci_sel);
#endif
	if (ret != 0) {
		vfe_err("sensor standby off error when selecting target device!\n");
		goto altend;
	}

	ret = v4l2_subdev_call(dev->sd, core, init, 0);
	if (ret != 0) {
		vfe_err("sensor initial error when selecting target device!\n");
		goto altend;
	}

	if (dev->sd_act != NULL) {
		struct actuator_para_t vcm_para;

		vcm_para.active_min = dev->isp_gen_set_pt->isp_ini_cfg.isp_3a_settings.vcm_min_code;
		vcm_para.active_max = dev->isp_gen_set_pt->isp_ini_cfg.isp_3a_settings.vcm_max_code;
		vfe_dbg(0, "min/max=%d/%d\n", dev->isp_gen_set_pt->isp_ini_cfg.isp_3a_settings.vcm_min_code,
		dev->isp_gen_set_pt->isp_ini_cfg.isp_3a_settings.vcm_max_code);
		v4l2_subdev_call(dev->sd_act, core, ioctl, ACT_INIT, &vcm_para);
	}

	bsp_csi_disable(dev->csi_sel);
	if (dev->is_isp_used) {
		vfe_ctrl_para_reset(dev);
		bsp_isp_disable();
		bsp_isp_enable();
		bsp_isp_init(&dev->isp_init_para);
		/* Set the initial flip */
		ctrl.id = V4L2_CID_VFLIP;
		ctrl.value = dev->ccm_cfg[i]->vflip;
		ret = v4l2_s_ctrl(NULL, dev->isp_sd->ctrl_handler, &ctrl);
		if (ret != 0) {
			vfe_err("isp s_ctrl V4L2_CID_VFLIP error when vidioc_s_input!input_num = %d\n", i);
		}
		ctrl.id = V4L2_CID_VFLIP_THUMB;
		ctrl.value = dev->ccm_cfg[i]->vflip;
		ret = v4l2_s_ctrl(NULL, dev->isp_sd->ctrl_handler, &ctrl);
		if (ret != 0)
			vfe_err("isp s_ctrl V4L2_CID_VFLIP_THUMB error when vidioc_s_input!input_num = %d\n", i);

		ctrl.id = V4L2_CID_HFLIP;
		ctrl.value = dev->ccm_cfg[i]->hflip;
		ret = v4l2_s_ctrl(NULL, dev->isp_sd->ctrl_handler, &ctrl);
		if (ret != 0)
			vfe_err("isp s_ctrl V4L2_CID_HFLIP error when vidioc_s_input!input_num = %d\n", i);

		ctrl.id = V4L2_CID_HFLIP_THUMB;
		ctrl.value = dev->ccm_cfg[i]->hflip;
		ret = v4l2_s_ctrl(NULL, dev->isp_sd->ctrl_handler, &ctrl);
		if (ret != 0)
			vfe_err("isp s_ctrl V4L2_CID_HFLIP error when vidioc_s_input!input_num = %d\n", i);
	} else {
		/* bsp_isp_exit(); */
		/* Set the initial flip */
		ctrl.id = V4L2_CID_VFLIP;
		ctrl.value = dev->ccm_cfg[i]->vflip;
		ret = v4l2_s_ctrl(NULL, dev->sd->ctrl_handler, &ctrl);
		if (ret != 0)
			vfe_warn("sensor V4L2_CID_VFLIP not defined when vidioc_s_input!input_num = %d\n", i);

		ctrl.id = V4L2_CID_HFLIP;
		ctrl.value = dev->ccm_cfg[i]->hflip;
		ret = v4l2_s_ctrl(NULL, dev->sd->ctrl_handler, &ctrl);
		if (ret != 0)
			vfe_warn("sensor V4L2_CID_HFLIP not defined when vidioc_s_input!input_num = %d\n", i);
	}

	ret = 0;
altend:
	dev->vfe_s_input_flag = 1;
	return ret;
}

static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
{
	struct vfe_dev *dev = video_drvdata(file);
	struct video_device *vdev = video_devdata(file);

	dev->cur_ch = (vdev->num - VID_N_OFF) < 0 ? 0 : (vdev->num - VID_N_OFF);
	if (dev->cur_ch > 0)
		return 0;

	vfe_dbg(0, "%s ,input_num = %d\n", __func__, i);
	return internal_s_input(dev, i);
}

struct vfe_command {
	char name[32];
	int v4l2_item;
	int isp_item;
};

static struct vfe_command vfe_power_line_frequency[] = {

	{"frequency disabled", V4L2_CID_POWER_LINE_FREQUENCY_DISABLED, FREQUENCY_DISABLED,},
	{"frequency 50hz", V4L2_CID_POWER_LINE_FREQUENCY_50HZ, FREQUENCY_50HZ,},
	{"frequency 60hz", V4L2_CID_POWER_LINE_FREQUENCY_60HZ, FREQUENCY_60HZ,},
	{"frequency auto", V4L2_CID_POWER_LINE_FREQUENCY_AUTO, FREQUENCY_AUTO,},
};

static struct vfe_command vfe_colorfx[] = {
	{"NONE        ",     V4L2_COLORFX_NONE,		COLORFX_NONE,},
	{"BW          ",     V4L2_COLORFX_BW,		COLORFX_BW,},
	{"SEPIA       ",     V4L2_COLORFX_SEPIA,	COLORFX_SEPIA,},
	{"NEGATIVE    ",     V4L2_COLORFX_NEGATIVE,	COLORFX_NEGATIVE,},
	{"EMBOSS      ",     V4L2_COLORFX_EMBOSS,	COLORFX_EMBOSS,},
	{"SKETCH      ",     V4L2_COLORFX_SKETCH,	COLORFX_SKETCH,},
	{"SKY_BLUE    ",     V4L2_COLORFX_SKY_BLUE,	COLORFX_SKY_BLUE,},
	{"GRASS_GREEN ",     V4L2_COLORFX_GRASS_GREEN,	COLORFX_GRASS_GREEN,},
	{"SKIN_WHITEN ",     V4L2_COLORFX_SKIN_WHITEN,	COLORFX_SKIN_WHITEN,},
	{"VIVID       ",     V4L2_COLORFX_VIVID,	COLORFX_VIVID,},
	{"AQUA        ",     V4L2_COLORFX_AQUA,		COLORFX_AQUA,},
	{"ART_FREEZE  ",     V4L2_COLORFX_ART_FREEZE,	COLORFX_ART_FREEZE,},
	{"SILHOUETTE  ",     V4L2_COLORFX_SILHOUETTE,	COLORFX_SILHOUETTE,},
	{"SOLARIZATION",     V4L2_COLORFX_SOLARIZATION,	COLORFX_SOLARIZATION,},
	{"ANTIQUE     ",     V4L2_COLORFX_ANTIQUE,	COLORFX_ANTIQUE,},
	{"SET_CBCR    ",     V4L2_COLORFX_SET_CBCR,	COLORFX_SET_CBCR,},
};

static struct vfe_command vfe_ae_mode[] = {
	{"EXPOSURE_AUTO",		V4L2_EXPOSURE_AUTO,			EXP_AUTO,},
	{"EXPOSURE_MANUAL",		V4L2_EXPOSURE_MANUAL,			EXP_MANUAL,},
	{"EXPOSURE_SHUTTER_PRIORITY",	V4L2_EXPOSURE_SHUTTER_PRIORITY,		EXP_AUTO,},
	{"EXPOSURE_APERTURE_PRIORITY",	V4L2_EXPOSURE_APERTURE_PRIORITY,	EXP_AUTO,},
};

static struct vfe_command vfe_wb[] = {
	{"WB_MANUAL       ",     V4L2_WHITE_BALANCE_MANUAL,	WB_MANUAL,},
	{"WB_AUTO         ",     V4L2_WHITE_BALANCE_AUTO,	WB_AUTO,},
	{"WB_INCANDESCENT ",     V4L2_WHITE_BALANCE_INCANDESCENT,	WB_INCANDESCENT,},
	{"WB_FLUORESCENT  ",     V4L2_WHITE_BALANCE_FLUORESCENT,	WB_FLUORESCENT,},
	{"WB_FLUORESCENT_H",     V4L2_WHITE_BALANCE_FLUORESCENT_H,    WB_FLUORESCENT_H,},
	{"WB_HORIZON      ",     V4L2_WHITE_BALANCE_HORIZON,    WB_HORIZON,},
	{"WB_DAYLIGHT     ",     V4L2_WHITE_BALANCE_DAYLIGHT,    WB_DAYLIGHT,},
	{"WB_FLASH        ",     V4L2_WHITE_BALANCE_FLASH,    WB_FLASH,},
	{"WB_CLOUDY       ",     V4L2_WHITE_BALANCE_CLOUDY,    WB_CLOUDY,},
	{"WB_SHADE        ",     V4L2_WHITE_BALANCE_SHADE,    WB_SHADE,},
};

static struct vfe_command vfe_iso[] = {
	{"ISO_SENSITIVITY_MANUAL",  V4L2_ISO_SENSITIVITY_MANUAL, ISO_MANUAL,},
	{"ISO_SENSITIVITY_AUTO",   V4L2_ISO_SENSITIVITY_AUTO,	ISO_AUTO,},
};
static struct vfe_command vfe_scene[] = {
	{"SCENE_MODE_NONE        ",     V4L2_SCENE_MODE_NONE,	SCENE_MODE_NONE},
	{"SCENE_MODE_BACKLIGHT   ",     V4L2_SCENE_MODE_BACKLIGHT,  SCENE_MODE_BACKLIGHT,},
	{"SCENE_MODE_BEACH_SNOW  ",     V4L2_SCENE_MODE_BEACH_SNOW,  SCENE_MODE_BEACH_SNOW,},
	{"SCENE_MODE_CANDLE_LIGHT",     V4L2_SCENE_MODE_CANDLE_LIGHT,  SCENE_MODE_CANDLE_LIGHT,},
	{"SCENE_MODE_DAWN_DUSK   ",     V4L2_SCENE_MODE_DAWN_DUSK,  SCENE_MODE_DAWN_DUSK,},
	{"SCENE_MODE_FALL_COLORS ",     V4L2_SCENE_MODE_FALL_COLORS,  SCENE_MODE_FALL_COLORS,},
	{"SCENE_MODE_FIREWORKS   ",     V4L2_SCENE_MODE_FIREWORKS,  SCENE_MODE_FIREWORKS,},
	{"SCENE_MODE_LANDSCAPE   ",     V4L2_SCENE_MODE_LANDSCAPE,  SCENE_MODE_LANDSCAPE,},
	{"SCENE_MODE_NIGHT       ",     V4L2_SCENE_MODE_NIGHT,  SCENE_MODE_NIGHT,},
	{"SCENE_MODE_PARTY_INDOOR",     V4L2_SCENE_MODE_PARTY_INDOOR,  SCENE_MODE_PARTY_INDOOR,},
	{"SCENE_MODE_PORTRAIT    ",     V4L2_SCENE_MODE_PORTRAIT,  SCENE_MODE_PORTRAIT,},
	{"SCENE_MODE_SPORTS      ",     V4L2_SCENE_MODE_SPORTS,  SCENE_MODE_SPORTS,},
	{"SCENE_MODE_SUNSET      ",     V4L2_SCENE_MODE_SUNSET,  SCENE_MODE_SUNSET,},
	{"SCENE_MODE_TEXT        ",     V4L2_SCENE_MODE_TEXT,  SCENE_MODE_TEXT,},
};

static struct vfe_command vfe_af_range[] = {
	{"AF_RANGE_AUTO",	V4L2_AUTO_FOCUS_RANGE_AUTO,	AF_RANGE_AUTO,},
	{"AF_RANGE_NORMAL",	V4L2_AUTO_FOCUS_RANGE_NORMAL,	AF_RANGE_NORMAL,},
	{"AF_RANGE_MACRO",	V4L2_AUTO_FOCUS_RANGE_MACRO,	AF_RANGE_MACRO,},
	{"AF_RANGE_INFINITY",	V4L2_AUTO_FOCUS_RANGE_INFINITY, AF_RANGE_INFINITY,},
};

static struct vfe_command vfe_flash_mode[] = {
	{"FLASH_LED_MODE_NONE	 ",	V4L2_FLASH_LED_MODE_NONE,	FLASH_MODE_OFF,},
	{"FLASH_LED_MODE_FLASH	 ",	V4L2_FLASH_LED_MODE_FLASH,	FLASH_MODE_ON,},
	{"FLASH_LED_MODE_TORCH	 ",	V4L2_FLASH_LED_MODE_TORCH,	FLASH_MODE_TORCH,},
	{"FLASH_LED_MODE_AUTO	 ",	V4L2_FLASH_LED_MODE_AUTO,	FLASH_MODE_AUTO,},
	{"FLASH_LED_MODE_RED_EYE",	V4L2_FLASH_LED_MODE_RED_EYE,	FLASH_MODE_RED_EYE,},
};

static struct vfe_command vfe_focus_status[] = {
	{"V4L2_AUTO_FOCUS_STATUS_IDLE	 ",	V4L2_AUTO_FOCUS_STATUS_IDLE,	AUTO_FOCUS_STATUS_IDLE,	},
	{"V4L2_AUTO_FOCUS_STATUS_BUSY	 ",	V4L2_AUTO_FOCUS_STATUS_BUSY,	AUTO_FOCUS_STATUS_BUSY, },
	{"V4L2_AUTO_FOCUS_STATUS_REACHED	 ",	V4L2_AUTO_FOCUS_STATUS_REACHED,		AUTO_FOCUS_STATUS_REACHED,},
	{"V4L2_AUTO_FOCUS_STATUS_BUSY	 ",	V4L2_AUTO_FOCUS_STATUS_BUSY,	V4L2_AUTO_FOCUS_STATUS_BUSY,},
	{"V4L2_AUTO_FOCUS_STATUS_BUSY",	V4L2_AUTO_FOCUS_STATUS_BUSY,	AUTO_FOCUS_STATUS_REFOCUS,},
	{"V4L2_AUTO_FOCUS_STATUS_BUSY	 ",	V4L2_AUTO_FOCUS_STATUS_BUSY,	AUTO_FOCUS_STATUS_FINDED,},
	{"V4L2_AUTO_FOCUS_STATUS_FAILED",	V4L2_AUTO_FOCUS_STATUS_FAILED,	AUTO_FOCUS_STATUS_FAILED,},
};

enum vfe_command_tpye {
	VFE_POWER_LINE_FREQUENCY,
	VFE_COLORFX,
	VFE_AE_MODE,
	VFE_WB,
	VFE_ISO,
	VFE_SCENE,
	VFE_AF_RANGE,
	VFE_FLASH_MODE,
	VFE_FOCUS_STATUS,
	VFE_COMMAND_MAX,
};

struct vfe_command_adapter {
	struct vfe_command *cmd_pt;
	int					size;
};

struct vfe_command_adapter vfe_cmd_adapter[] = {

	{&vfe_power_line_frequency[0], ARRAY_SIZE(vfe_power_line_frequency)},
	{&vfe_colorfx[0], ARRAY_SIZE(vfe_colorfx)},
	{&vfe_ae_mode[0], ARRAY_SIZE(vfe_ae_mode)},
	{&vfe_wb[0], ARRAY_SIZE(vfe_wb)},
	{&vfe_iso[0], ARRAY_SIZE(vfe_iso)},
	{&vfe_scene[0], ARRAY_SIZE(vfe_scene)},
	{&vfe_af_range[0], ARRAY_SIZE(vfe_af_range)},
	{&vfe_flash_mode[0], ARRAY_SIZE(vfe_flash_mode)},
	{&vfe_focus_status[0], ARRAY_SIZE(vfe_focus_status)},
};

enum {
	V4L2_TO_ISP,
	ISP_TO_V4L2,
};

int vfe_v4l2_isp(int type, int cmd, int flag)
{
	struct vfe_command_adapter cmd_adapter;
	int i;

	if (type >= ARRAY_SIZE(vfe_cmd_adapter))
		vfe_err("vfe command tpye ERR, type = %d\n", type);

	cmd_adapter = vfe_cmd_adapter[type];
	if (flag == V4L2_TO_ISP) {
		for (i = 0; i < cmd_adapter.size; i++) {
			if (cmd == cmd_adapter.cmd_pt[i].v4l2_item) {
				vfe_dbg(0, "vfe set %s, cmd = %d\n", cmd_adapter.cmd_pt[i].name, cmd);
				return cmd_adapter.cmd_pt[i].isp_item;
			}
		}
	} else if (flag == ISP_TO_V4L2) {
		for (i = 0; i < cmd_adapter.size; i++) {
			if (cmd == cmd_adapter.cmd_pt[i].isp_item) {
				vfe_dbg(0, "vfe get %s, cmd = %d\n", cmd_adapter.cmd_pt[i].name, cmd);
				return cmd_adapter.cmd_pt[i].v4l2_item;
			}
		}
	}
	vfe_err("command conver ERR, cmd = %d\n", cmd);

	return 0;
}

static int vidioc_g_parm(struct file *file, void *priv,
						struct v4l2_streamparm *parms)
{
	struct vfe_dev *dev = video_drvdata(file);
	int ret;

	ret = sensor_g_parm(dev->sd, parms);
	if (ret < 0)
		vfe_warn("v4l2 sub device g_parm fail!\n");

	return ret;
}

static int vidioc_s_parm(struct file *file, void *priv,
						struct v4l2_streamparm *parms)
{
	struct vfe_dev *dev = video_drvdata(file);
	int ret;

	if (parms->parm.capture.capturemode != V4L2_MODE_VIDEO && \
				parms->parm.capture.capturemode != V4L2_MODE_IMAGE && \
				parms->parm.capture.capturemode != V4L2_MODE_PREVIEW) {
		parms->parm.capture.capturemode = V4L2_MODE_PREVIEW;
	}

	dev->capture_mode = parms->parm.capture.capturemode;

	ret = sensor_s_parm(dev->sd, parms);
	if (ret < 0)
		vfe_warn("v4l2 sub device s_parm error!\n");

	ret = sunxi_csi_subdev_s_parm(dev->csi_sd, parms);
	if (ret < 0)
		vfe_warn("v4l2 sub device s_parm error!\n");

	return ret;
}

int isp_ae_stat_req(struct file *file, struct v4l2_fh *fh, struct isp_stat_buf *ae_buf)
{
	struct vfe_dev *dev = video_drvdata(file);
	int ret = 0;

	ae_buf->buf_size = ISP_STAT_AE_MEM_SIZE;
	ret = copy_to_user(ae_buf->buf,
			    dev->isp_gen_set_pt->stat.ae_buf,
			    ae_buf->buf_size);
	return ret;
}

int isp_gamma_req(struct file *file, struct v4l2_fh *fh, struct isp_stat_buf *gamma_buf)
{
	struct vfe_dev *dev = video_drvdata(file);
	int ret = 0;

	gamma_buf->buf_size = ISP_GAMMA_MEM_SIZE;
	ret = copy_to_user(gamma_buf->buf,
			    dev->isp_gen_set_pt->isp_ini_cfg.isp_tunning_settings.gamma_tbl_post,
			    gamma_buf->buf_size);
	return ret;
}

int isp_hist_stat_req(struct file *file, struct v4l2_fh *fh, struct isp_stat_buf *hist_buf)
{
	struct vfe_dev *dev = video_drvdata(file);
	int ret = 0;

	hist_buf->buf_size = ISP_STAT_HIST_MEM_SIZE;
	ret = copy_to_user(hist_buf->buf,
			    dev->isp_gen_set_pt->stat.hist_buf,
			    hist_buf->buf_size);
	return ret;
}

int isp_af_stat_req(struct file *file, struct v4l2_fh *fh, struct isp_stat_buf *af_buf)
{
	struct vfe_dev *dev = video_drvdata(file);
	int ret = 0;

	af_buf->buf_size = ISP_STAT_AF_MEM_SIZE;

	ret = copy_to_user(af_buf->buf,
			    dev->isp_gen_set_pt->stat.af_buf,
			    af_buf->buf_size);
	return 0;
}

static int isp_exif_req(struct file *file, struct v4l2_fh *fh, struct isp_exif_attribute *exif_attr)
{
	struct vfe_dev *dev = video_drvdata(file);
	struct sensor_exif_attribute exif;

	if (dev->isp_gen_set_pt && dev->is_bayer_raw) {
		exif_attr->fnumber = dev->isp_gen_set_pt->isp_ini_cfg.isp_3a_settings.fno;
		if (exif_attr->fnumber < 40)
			exif_attr->fnumber = 240;
		exif_attr->focal_length = dev->isp_gen_set_pt->isp_ini_cfg.isp_tunning_settings.focus_length;
		if (dev->isp_gen_set_pt->isp_ini_cfg.isp_test_settings.isp_test_mode == ISP_TEST_ALL_ENABLE) {
			if (exif_attr->focal_length < 40)
				exif_attr->focal_length = 400;
		} else
			exif_attr->focal_length = dev->isp_3a_result_pt->real_vcm_pos;

		exif_attr->brightness = dev->isp_gen_set_pt->ae_lum;
		exif_attr->exposure_bias = dev->isp_gen_set_pt->exp_settings.exp_compensation;
		exif_attr->flash_fire = dev->isp_gen_set_pt->exp_settings.flash_open;
		exif_attr->iso_speed = (dev->isp_3a_result_pt->exp_analog_gain * dev->isp_3a_result_pt->exp_digital_gain) * 50 / 4096;
		exif_attr->exposure_time.numerator = 1;
		exif_attr->shutter_speed.numerator = 1;
		if (dev->isp_3a_result_pt->exp_time != 0) {
			exif_attr->exposure_time.denominator = 1000000/dev->isp_3a_result_pt->exp_time;
			exif_attr->shutter_speed.denominator = 1000000/dev->isp_3a_result_pt->exp_time;
		} else {
			exif_attr->exposure_time.denominator = 10000;
			exif_attr->shutter_speed.denominator = 10000;
		}
		exif_attr->reserved[0] = dev->isp_3a_result_pt->real_vcm_pos;
		exif_attr->reserved[1] = dev->isp_gen_set_pt->color_temp;
	} else {
		if (v4l2_subdev_call(dev->sd, core, ioctl, GET_SENSOR_EXIF, &exif) != 0) {
			exif_attr->fnumber = 240;
			exif_attr->focal_length = 180;
			exif_attr->brightness = 128;
			exif_attr->exposure_bias = dev->ctrl_para.exp_bias;
			exif_attr->flash_fire = 0;
			exif_attr->iso_speed = 200;
			exif_attr->exposure_time.numerator = 1;
			exif_attr->exposure_time.denominator = 20;
			exif_attr->shutter_speed.numerator = 1;
			exif_attr->shutter_speed.denominator = 24;
		} else {
			exif_attr->fnumber = exif.fnumber;
			exif_attr->focal_length = exif.focal_length;
			exif_attr->brightness = exif.brightness;
			exif_attr->exposure_bias = dev->ctrl_para.exp_bias;
			exif_attr->flash_fire = exif.flash_fire;
			exif_attr->iso_speed = exif.iso_speed;
			exif_attr->exposure_time.numerator = exif.exposure_time_num;
			exif_attr->exposure_time.denominator = exif.exposure_time_den;
			exif_attr->shutter_speed.numerator = exif.exposure_time_num;
			exif_attr->shutter_speed.denominator = exif.exposure_time_den;
		}
	}

	return 0;
}

static int __isp_auto_focus_win(struct vfe_dev *dev, struct v4l2_win_setting *af_win)
{
	int i;
	struct ccm_config *ccm_curr = &dev->ccm_cfg_content[dev->input];

	if (af_win->win_num == 0) {
		bsp_isp_s_auto_focus_win_num(dev->isp_gen_set_pt, AF_AUTO_WIN, NULL);
	} else if (af_win->win_num > V4L2_MAX_WIN_NUM) {
		return -EINVAL;
	} else {
		struct v4l2_win_coordinate *win_coor = &af_win->coor[0];

		for (i = 0; i < af_win->win_num; i++) {
			if (ccm_curr->vflip == 1) {
				dev->ctrl_para.af_coor[i].y1 = -win_coor[0].y1;
				dev->ctrl_para.af_coor[i].y2 = -win_coor[0].y2;
			} else {
				dev->ctrl_para.af_coor[i].y1 = win_coor[i].y1;
				dev->ctrl_para.af_coor[i].y2 = win_coor[i].y2;
			}
			if (ccm_curr->hflip == 1) {
				dev->ctrl_para.af_coor[i].x1 = -win_coor[0].x1;
				dev->ctrl_para.af_coor[i].x2 = -win_coor[0].x2;
			} else {
				dev->ctrl_para.af_coor[i].x1 = win_coor[0].x1;
				dev->ctrl_para.af_coor[i].x2 = win_coor[0].x2;
			}
		}
		bsp_isp_s_auto_focus_win_num(dev->isp_gen_set_pt, AF_NUM_WIN, &dev->ctrl_para.af_coor[0]);
	}

	return 0;
}

static int __isp_auto_exp_win(struct vfe_dev *dev, struct v4l2_win_setting *ae_win)
{
	int i;
	struct ccm_config *ccm_curr = &dev->ccm_cfg_content[dev->input];

	if (ae_win->win_num == 0) {
		bsp_isp_s_auto_exposure_win_num(dev->isp_gen_set_pt, AE_AUTO_WIN, NULL);
	} else if (ae_win->win_num > V4L2_MAX_WIN_NUM) {
		return -EINVAL;
	} else {
		struct v4l2_win_coordinate *win_coor = &ae_win->coor[0];

		for (i = 0; i < ae_win->win_num; i++) {
			if (ccm_curr->vflip == 1) {
				dev->ctrl_para.ae_coor[i].y1 = -win_coor[0].y1;
				dev->ctrl_para.ae_coor[i].y2 = -win_coor[0].y2;
			} else {
				dev->ctrl_para.ae_coor[i].y1 = win_coor[i].y1;
				dev->ctrl_para.ae_coor[i].y2 = win_coor[i].y2;
			}
			if (ccm_curr->hflip == 1) {
				dev->ctrl_para.ae_coor[i].x1 = -win_coor[0].x1;
				dev->ctrl_para.ae_coor[i].x2 = -win_coor[0].x2;
			} else {
				dev->ctrl_para.ae_coor[i].x1 = win_coor[0].x1;
				dev->ctrl_para.ae_coor[i].x2 = win_coor[0].x2;
			}
		}
		dev->isp_gen_set_pt->win.hist_coor.x1 = win_coor[0].x1;
		dev->isp_gen_set_pt->win.hist_coor.y1 = win_coor[0].y1;
		dev->isp_gen_set_pt->win.hist_coor.x2 = win_coor[0].x2;
		dev->isp_gen_set_pt->win.hist_coor.y2 = win_coor[0].y2;
		bsp_isp_s_auto_exposure_win_num(dev->isp_gen_set_pt, AE_SINGLE_WIN, &dev->ctrl_para.ae_coor[0]);
	}

	return 0;
}

int vidioc_auto_focus_win(struct file *file, struct v4l2_fh *fh, struct v4l2_win_setting *af_win)
{
	struct vfe_dev *dev = video_drvdata(file);
	int ret = 0;

	if (dev->isp_gen_set_pt && dev->is_bayer_raw)
		ret = __isp_auto_focus_win(dev, af_win);
	else
		ret = v4l2_subdev_call(dev->sd, core, ioctl, SET_AUTO_FOCUS_WIN, af_win);

	return ret;
}

int vidioc_auto_exposure_win(struct file *file, struct v4l2_fh *fh, struct v4l2_win_setting *exp_win)
{
	struct vfe_dev *dev = video_drvdata(file);
	int ret = 0;

	if (dev->isp_gen_set_pt && dev->is_bayer_raw)
		ret = __isp_auto_exp_win(dev, exp_win);
	else
		ret = v4l2_subdev_call(dev->sd, core, ioctl, SET_AUTO_EXPOSURE_WIN, exp_win);

	return ret;
}

int vidioc_hdr_ctrl(struct file *file, struct v4l2_fh *fh, struct isp_hdr_ctrl *hdr)
{
	struct vfe_dev *dev = video_drvdata(file);

	if (dev->isp_gen_set_pt && dev->is_bayer_raw) {
		if (hdr->flag == HDR_CTRL_SET) {
			bsp_isp_s_hdr(dev->isp_gen_set_pt, (struct hdr_setting_t *)(&hdr->hdr_t));
			dev->isp_3a_result_pt->image_quality.bits.hdr_cnt = 0;
		} else {
			hdr->count = dev->isp_gen_set_pt->hdr_setting.frames_count - 1;
			memcpy(&hdr->hdr_t, &dev->isp_gen_set_pt->hdr_setting, sizeof(struct isp_hdr_setting_t));
		}

		return 0;
	}

	return -EINVAL;
}

int vidioc_set_subchannel(struct file *file, struct v4l2_fh *fh, struct v4l2_pix_format *sub)
{
	int ret = 0;
	struct vfe_dev *dev = video_drvdata(file);

	if (!dev->is_isp_used) {
		vfe_err("isp must be set first when set subchannel\n");
		return -1;
	}
	ret = v4l2_subdev_call(dev->isp_sd, core, ioctl, VIDIOC_SUNXI_ISP_SUB_CH_CFG, sub);
	if (ret < 0) {
		vfe_err("vidioc_set_subchannel error! ret = %d\n", ret);
		return ret;
	}

	dev->buf_byte_size = sub->sizeimage;
	dev->isp_gen_set_pt->double_ch_flag = 1;
	dev->thumb_width  = sub->width;
	dev->thumb_height = sub->height;

	return ret;
}

int vidioc_set_rotchannel(struct file *file, struct v4l2_fh *fh, struct rot_channel_cfg *rot)
{
	int ret = 0;
	struct vfe_dev *dev = video_drvdata(file);

	if (!dev->is_isp_used) {
		vfe_err("isp must be set first when set rotchannel\n");
		return -1;
	}
	ret = v4l2_subdev_call(dev->isp_sd, core, ioctl, VIDIOC_SUNXI_ISP_ROT_CH_CFG, rot);
	if (ret < 0) {
		vfe_err("vidioc_set_rotchannel error! ret = %d\n", ret);
		return ret;
	}
	dev->buf_byte_size = rot->pix.sizeimage;

	return ret;
}
static long vfe_param_handler(struct file *file, void *priv,
		bool valid_prio, unsigned int cmd, void *param)
{
	int ret = 0;
	struct v4l2_fh *fh = (struct v4l2_fh *)priv;
	struct isp_stat_buf *stat = (struct isp_stat_buf *)param;

	switch (cmd) {
	case VIDIOC_ISP_AE_STAT_REQ:
		ret = isp_ae_stat_req(file, fh, stat);
		break;
	case VIDIOC_ISP_AF_STAT_REQ:
		ret = isp_af_stat_req(file, fh, stat);
		break;
	case VIDIOC_ISP_HIST_STAT_REQ:
		ret = isp_hist_stat_req(file, fh, stat);
		break;
	case VIDIOC_ISP_EXIF_REQ:
		ret = isp_exif_req(file, fh, (struct isp_exif_attribute *)param);
		break;
	case VIDIOC_ISP_GAMMA_REQ:
		ret = isp_gamma_req(file, fh, stat);
		break;
	case VIDIOC_AUTO_FOCUS_WIN:
		ret = vidioc_auto_focus_win(file, fh, (struct v4l2_win_setting *)param);
		break;
	case VIDIOC_AUTO_EXPOSURE_WIN:
		ret = vidioc_auto_exposure_win(file, fh, (struct v4l2_win_setting *)param);
		break;
	case VIDIOC_HDR_CTRL:
		ret = vidioc_hdr_ctrl(file, fh, (struct isp_hdr_ctrl *)param);
		break;
	case VIDIOC_SET_SUBCHANNEL:
		ret = vidioc_set_subchannel(file, fh, (struct v4l2_pix_format *)param);
		break;
	case VIDIOC_SET_ROTCHANNEL:
		ret = vidioc_set_rotchannel(file, fh, (struct rot_channel_cfg *)param);
		break;
	default:
		ret = -ENOTTY;
	}

	return ret;
}

static ssize_t vfe_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
{
	struct vfe_dev *dev = video_drvdata(file);
	struct video_device *vdev = video_devdata(file);
	int ret = 0;

	mutex_lock(&dev->buf_lock);
	dev->cur_ch = (vdev->num - VID_N_OFF) < 0 ? 0 : (vdev->num - VID_N_OFF);
	if (vfe_is_generating(dev)) {
		ret = vb2_read(&dev->vb_vidq[dev->cur_ch], data, count, ppos,
					file->f_flags & O_NONBLOCK);
	} else {
		vfe_err("csi is not generating!\n");
		ret = -EINVAL;
	}
	mutex_unlock(&dev->buf_lock);

	return ret;
}

static unsigned int vfe_poll(struct file *file, struct poll_table_struct *wait)
{
	struct vfe_dev *dev = video_drvdata(file);
	struct video_device *vdev = video_devdata(file);
	int ret = 0;

	mutex_lock(&dev->buf_lock);
	dev->cur_ch = (vdev->num - VID_N_OFF) < 0 ? 0 : (vdev->num - VID_N_OFF);
	if (vfe_is_generating(dev)) {
		ret = vb2_poll(&dev->vb_vidq[dev->cur_ch], file, wait);
	} else {
		vfe_err("csi is not generating!\n");
		ret = -EINVAL;
	}
	mutex_unlock(&dev->buf_lock);

	return ret;
}

void vfe_clk_open(struct vfe_dev *dev)
{
	vfe_print("..........................vfe clk open!.......................\n");
	v4l2_subdev_call(dev->csi_sd, core, s_power, 1);
	v4l2_subdev_call(dev->mipi_sd, core, s_power, 1);
}

void vfe_clk_close(struct vfe_dev *dev)
{
	vfe_print("..........................vfe clk close!.......................\n");
	v4l2_subdev_call(dev->csi_sd, core, s_power, 0);
	v4l2_subdev_call(dev->mipi_sd, core, s_power, 0);
}

static void vfe_suspend_trip(struct vfe_dev *dev);
static void vfe_resume_trip(struct vfe_dev *dev);

static int __vfe_open(struct vfe_dev *dev)
{
	int ret;

	vfe_print("vfe_open\n");
	if (vfe_is_opened(dev)) {
		vfe_err("device open busy\n");
		ret = -EBUSY;
		goto open_end;
	}
#ifdef CONFIG_DEVFREQ_DRAM_FREQ_WITH_SOFT_NOTIFY
	dramfreq_master_access(MASTER_CSI, true);
#endif
	vfe_resume_trip(dev);
#ifdef USE_SPECIFIC_CCI
	csi_cci_init_helper(dev->cci_sel);
#endif
	if (dev->ccm_cfg[0]->is_isp_used || dev->ccm_cfg[1]->is_isp_used) {
		/* must be after ahb and core clock enable */
		ret = v4l2_subdev_call(dev->isp_sd, core, init, 0);
		if (ret < 0) {
			vfe_err("ISP init error at %s\n", __func__);
			return ret;
		}
		ret = isp_resource_request(dev);
		if (ret) {
			vfe_err("isp_resource_request error at %s\n", __func__);
			return ret;
		}
		vfe_dbg(0, "tasklet init !\n");
		INIT_WORK(&dev->isp_isr_bh_task, isp_isr_bh_handle);
		INIT_WORK(&dev->isp_isr_set_sensor_task, isp_isr_set_sensor_handle);
	}
	dev->input = -1;
	vfe_start_opened(dev);
	vfe_init_isp_log(dev);
open_end:
	if (ret != 0)
		vfe_print("vfe_open busy\n");
	else
		vfe_print("vfe_open ok\n");

	return ret;
}

static int vfe_open(struct file *file)
{
	struct vfe_dev *dev = video_drvdata(file);
	struct video_device *vdev = video_devdata(file);
	int ret = 0;

	mutex_lock(&dev->buf_lock);
	dev->cur_ch = (vdev->num - VID_N_OFF) < 0 ? 0 : (vdev->num - VID_N_OFF);
	dev->first_flag[dev->cur_ch] = 0;
	if (dev->cur_ch > 0) {
		mutex_unlock(&dev->buf_lock);
		return 0;
	}
	dev->special_active = 0;
	ret = __vfe_open(dev);
	mutex_unlock(&dev->buf_lock);

	return ret;
}

static int __vfe_close(struct vfe_dev *dev)
{
	int ret;

	vfe_print("vfe_close\n");
	vfe_stop_generating(dev);
	if (dev->vfe_s_input_flag == 1) {
		if (dev->sd_act != NULL)
			v4l2_subdev_call(dev->sd_act, core, ioctl, ACT_SOFT_PWDN, 0);

		ret = vfe_set_sensor_power_off(dev);
		if (ret != 0)
			vfe_err("sensor power off error at device number when csi close!\n");

		dev->vfe_s_input_flag = 0;
	} else
		vfe_print("vfe select input flag = %d, s_input have not be used .\n", dev->vfe_s_input_flag);
	/* hardware */
	bsp_csi_int_disable(dev->csi_sel, dev->cur_ch, CSI_INT_ALL);
	v4l2_subdev_call(dev->csi_sd, video, s_stream, 0);
	bsp_csi_disable(dev->csi_sel);
	if (dev->is_isp_used)
		bsp_isp_disable();
	if (dev->mbus_type == V4L2_MBUS_CSI2_DPHY) {
		bsp_mipi_csi_protocol_disable(dev->mipi_sel);
		bsp_mipi_csi_dphy_disable(dev->mipi_sel);
		bsp_mipi_csi_dphy_exit(dev->mipi_sel);
	}
	if (dev->is_isp_used)
		bsp_isp_exit();
	flush_delayed_work(&dev->probe_work);

	if (dev->ccm_cfg[0]->is_isp_used || dev->ccm_cfg[1]->is_isp_used) {
		flush_work(&dev->isp_isr_bh_task);
		flush_work(&dev->isp_isr_set_sensor_task);
		/* resource */
		isp_resource_release(dev);
	}
	if (dev->is_bayer_raw)
		mutex_destroy(&dev->isp_3a_result_mutex);
	vfe_stop_opened(dev);
	dev->ctrl_para.prev_exp_line = 0;
	dev->ctrl_para.prev_ana_gain = 1;
	vfe_suspend_trip(dev);
	vfe_print("vfe_close end\n");
	vfe_exit_isp_log(dev);
#ifdef CONFIG_DEVFREQ_DRAM_FREQ_WITH_SOFT_NOTIFY
	dramfreq_master_access(MASTER_CSI, false);
#endif
	return 0;
}

static int vfe_close(struct file *file)
{
	struct vfe_dev *dev = video_drvdata(file);
	struct video_device *vdev = video_devdata(file);
	int ret = 0;

	mutex_lock(&dev->buf_lock);
	dev->cur_ch = (vdev->num - VID_N_OFF) < 0 ? 0 : (vdev->num - VID_N_OFF);
	vb2_queue_release(&dev->vb_vidq[dev->cur_ch]);
	if (dev->cur_ch > 0) {
		mutex_unlock(&dev->buf_lock);
		return 0;
	}
	ret = __vfe_close(dev);
	mutex_unlock(&dev->buf_lock);

	return ret;
}

static int vfe_mmap(struct file *file, struct vm_area_struct *vma)
{
	struct vfe_dev *dev = video_drvdata(file);
	struct video_device *vdev = video_devdata(file);
	int ret = 0;

	mutex_lock(&dev->buf_lock);
	dev->cur_ch = (vdev->num - VID_N_OFF) < 0 ? 0 : (vdev->num - VID_N_OFF);
	ret = vb2_mmap(&dev->vb_vidq[dev->cur_ch], vma);
	mutex_unlock(&dev->buf_lock);

	return ret;
}

static int vfe_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
{
	int ret = 0;
	struct vfe_dev *dev = container_of(ctrl->handler, struct vfe_dev, ctrl_handler);
	struct v4l2_control c;

	c.id = ctrl->id;

	if (dev->is_isp_used && dev->is_bayer_raw) {
		switch (ctrl->id) {
		case V4L2_CID_EXPOSURE:
			v4l2_g_ctrl(dev->sd->ctrl_handler, &c);
			ctrl->val = c.value;
			break;
		case V4L2_CID_GAIN:
			if (dev->isp_gen_set_pt->isp_ini_cfg.isp_test_settings.isp_test_mode == ISP_TEST_ALL_ENABLE ||
					dev->isp_gen_set_pt->isp_ini_cfg.isp_test_settings.isp_test_mode == ISP_TEST_MANUAL) {
				ctrl->val = CLIP(CLIP(dev->isp_3a_result_pt->exp_analog_gain, 16, 255) |
				(CLIP(dev->isp_gen_set_pt->sharp_cfg_to_hal[1], 0, 4095) << V4L2_SHARP_LEVEL_SHIFT)  |
				(CLIP(dev->isp_gen_set_pt->sharp_cfg_to_hal[0], 0, 63) << V4L2_SHARP_MIN_SHIFT) |
				(CLIP(dev->isp_gen_set_pt->isp_ini_cfg.isp_tunning_settings.color_denoise_level, 0, 31) << V4L2_NDF_SHIFT), 0, 0xffffffff);
			} else {
				ctrl->val = CLIP(dev->isp_3a_result_pt->exp_analog_gain, 16, 255);
			}
			break;
		case V4L2_CID_HOR_VISUAL_ANGLE:
			ctrl->val = dev->isp_gen_set_pt->isp_ini_cfg.isp_tunning_settings.hor_visual_angle;
			break;
		case V4L2_CID_VER_VISUAL_ANGLE:
			ctrl->val = dev->isp_gen_set_pt->isp_ini_cfg.isp_tunning_settings.ver_visual_angle;
			break;
		case V4L2_CID_FOCUS_LENGTH:
			ctrl->val = dev->isp_gen_set_pt->isp_ini_cfg.isp_tunning_settings.focus_length;
			break;
		case V4L2_CID_R_GAIN:
			ctrl->val = dev->isp_gen_set_pt->module_cfg.wb_gain_cfg.wb_gain.r_gain;
			break;
		case V4L2_CID_G_GAIN:
			ctrl->val = dev->isp_gen_set_pt->module_cfg.wb_gain_cfg.wb_gain.gr_gain;
			break;
		case V4L2_CID_B_GAIN:
			ctrl->val = dev->isp_gen_set_pt->module_cfg.wb_gain_cfg.wb_gain.b_gain;
			break;
		case V4L2_CID_3A_LOCK:
			if (dev->isp_gen_set_pt->exp_settings.exposure_lock == ISP_TRUE)
				ctrl->val |= V4L2_LOCK_EXPOSURE;
			else
				ctrl->val &= ~V4L2_LOCK_EXPOSURE;

			if (dev->isp_gen_set_pt->wb_settings.white_balance_lock == ISP_TRUE)
				ctrl->val |= V4L2_LOCK_WHITE_BALANCE;
			else
				ctrl->val &= ~V4L2_LOCK_WHITE_BALANCE;

			if (dev->isp_gen_set_pt->af_settings.focus_lock == ISP_TRUE)
				ctrl->val |= V4L2_LOCK_FOCUS;
			else
				ctrl->val &= ~V4L2_LOCK_FOCUS;

			break;
		case V4L2_CID_AUTO_FOCUS_STATUS:  /* Read-Only */
			ctrl->val = vfe_v4l2_isp(VFE_FOCUS_STATUS, dev->isp_3a_result_pt->af_status, ISP_TO_V4L2);
			break;
		case V4L2_CID_SENSOR_TYPE:
			ctrl->val = dev->is_bayer_raw;
			break;
		case V4L2_CID_VFLIP:
			ret = v4l2_g_ctrl(dev->sd->ctrl_handler, &c);
			ctrl->val = c.value;
			break;
		case V4L2_CID_HFLIP:
			ret = v4l2_g_ctrl(dev->sd->ctrl_handler, &c);
			ctrl->val = c.value;
			break;
		default:
			return -EINVAL;
		}
		vfe_dbg(0, "vfe_g_volatile_ctrl: %s, last value: 0x%x\n", ctrl->name, ctrl->val);

		return 0;
	} else {
		switch (ctrl->id) {
		case V4L2_CID_SENSOR_TYPE:
			c.value = dev->is_bayer_raw;
			break;
		case V4L2_CID_FLASH_LED_MODE:
			ret = v4l2_g_ctrl(dev->flash_sd->ctrl_handler, &c);
			break;
		case V4L2_CID_AUTO_FOCUS_STATUS:
			ret = v4l2_g_ctrl(dev->sd->ctrl_handler, &c);
			if (c.value != V4L2_AUTO_FOCUS_STATUS_BUSY)
				sunxi_flash_stop(dev->flash_sd);
			break;
		case V4L2_CID_VFLIP:
			ret = v4l2_g_ctrl(dev->sd->ctrl_handler, &c);
			ctrl->val = c.value;
			break;
		case V4L2_CID_HFLIP:
			ret = v4l2_g_ctrl(dev->sd->ctrl_handler, &c);
			ctrl->val = c.value;
			break;
		default:
			ret = v4l2_g_ctrl(dev->sd->ctrl_handler, &c);
			break;
		}
		ctrl->val = c.value;
		if (ret < 0)
			vfe_warn("v4l2 sub device g_ctrl fail!\n");
	}
	return ret;
}

static int vfe_s_ctrl(struct v4l2_ctrl *ctrl)
{
	struct vfe_dev *dev = container_of(ctrl->handler, struct vfe_dev, ctrl_handler);
	int ret = 0;
	struct actuator_ctrl_word_t vcm_ctrl;
	struct v4l2_control c;

	c.id = ctrl->id;
	c.value = ctrl->val;
	vfe_dbg(0, "s_ctrl: %s, set value: 0x%x\n", ctrl->name, ctrl->val);

	if (dev->is_isp_used && dev->is_bayer_raw) {
		switch (ctrl->id) {
		case V4L2_CID_BRIGHTNESS:
			bsp_isp_s_brightness(dev->isp_gen_set_pt, ctrl->val);
			break;
		case V4L2_CID_CONTRAST:
			bsp_isp_s_contrast(dev->isp_gen_set_pt, ctrl->val);
			break;
		case V4L2_CID_SATURATION:
			bsp_isp_s_saturation(dev->isp_gen_set_pt, ctrl->val * 25);
			break;
		case V4L2_CID_HUE:
			bsp_isp_s_hue(dev->isp_gen_set_pt, ctrl->val);
			break;
		case V4L2_CID_AUTO_WHITE_BALANCE:
			if (ctrl->val == 0)
				bsp_isp_s_auto_white_balance(dev->isp_gen_set_pt, WB_MANUAL);
			else
				bsp_isp_s_auto_white_balance(dev->isp_gen_set_pt, WB_AUTO);
			dev->ctrl_para.auto_wb = ctrl->val;
			break;
		case V4L2_CID_EXPOSURE:
			ret = v4l2_s_ctrl(NULL, dev->sd->ctrl_handler, &c);
			break;
		case V4L2_CID_AUTOGAIN:
			if (ctrl->val == 0)
				bsp_isp_s_exposure(dev->isp_gen_set_pt, ISO_MANUAL);
			else
				bsp_isp_s_exposure(dev->isp_gen_set_pt, ISO_AUTO);
			break;
		case V4L2_CID_GAIN:
			ret = v4l2_s_ctrl(NULL, dev->sd->ctrl_handler, &c);
			break;
		case V4L2_CID_POWER_LINE_FREQUENCY:
			bsp_isp_s_power_line_frequency(dev->isp_gen_set_pt,
					vfe_v4l2_isp(VFE_POWER_LINE_FREQUENCY, ctrl->val, V4L2_TO_ISP));
			break;
		case V4L2_CID_HUE_AUTO:
			bsp_isp_s_hue_auto(dev->isp_gen_set_pt, ctrl->val);
			break;
		case V4L2_CID_WHITE_BALANCE_TEMPERATURE:
			bsp_isp_s_white_balance_temperature(dev->isp_gen_set_pt, ctrl->val);
			break;
		case V4L2_CID_SHARPNESS:
			bsp_isp_s_sharpness(dev->isp_gen_set_pt, ctrl->val);
			break;
		case V4L2_CID_CHROMA_AGC:
			bsp_isp_s_chroma_agc(dev->isp_gen_set_pt, ctrl->val);
			break;
		case V4L2_CID_COLORFX:
			bsp_isp_s_colorfx(dev->isp_gen_set_pt, vfe_v4l2_isp(VFE_COLORFX, ctrl->val, V4L2_TO_ISP));
			break;
		case V4L2_CID_AUTOBRIGHTNESS:
			bsp_isp_s_auto_brightness(dev->isp_gen_set_pt, ctrl->val);
			break;
		case V4L2_CID_BAND_STOP_FILTER:
			bsp_isp_s_band_stop_filter(dev->isp_gen_set_pt, ctrl->val);
			break;
		case V4L2_CID_ILLUMINATORS_1:
			bsp_isp_s_illuminators_1(dev->isp_gen_set_pt, ctrl->val);
			break;
		case V4L2_CID_ILLUMINATORS_2:
			bsp_isp_s_illuminators_2(dev->isp_gen_set_pt, ctrl->val);
			break;
		case V4L2_CID_EXPOSURE_AUTO:
			bsp_isp_s_exposure_auto(dev->isp_gen_set_pt,
					vfe_v4l2_isp(VFE_AE_MODE, ctrl->val, V4L2_TO_ISP));
			dev->ctrl_para.exp_auto_mode = ctrl->val;
			break;
		case V4L2_CID_EXPOSURE_ABSOLUTE:
			bsp_isp_s_exposure_absolute(dev->isp_gen_set_pt, ctrl->val);
			break;
		case V4L2_CID_EXPOSURE_AUTO_PRIORITY:
			bsp_isp_s_exposure_auto_priority(dev->isp_gen_set_pt, ctrl->val);
			break;
		case V4L2_CID_FOCUS_ABSOLUTE:
			bsp_isp_s_focus_absolute(dev->isp_gen_set_pt, ctrl->val);
			break;
		case V4L2_CID_FOCUS_RELATIVE:
			bsp_isp_s_focus_relative(dev->isp_gen_set_pt, ctrl->val);
			break;
		case V4L2_CID_FOCUS_AUTO:
			dev->isp_3a_result_pt->af_status = AUTO_FOCUS_STATUS_REFOCUS;
			bsp_isp_s_focus_auto(dev->isp_gen_set_pt, ctrl->val);
			dev->ctrl_para.auto_focus = ctrl->val;
			break;
		case V4L2_CID_AUTO_EXPOSURE_BIAS:
			bsp_isp_s_auto_exposure_bias(dev->isp_gen_set_pt, ctrl->qmenu_int[ctrl->val]);
			dev->ctrl_para.exp_bias = ctrl->qmenu_int[ctrl->val];
			break;
		case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:
			bsp_isp_s_auto_n_preset_white_balance(dev->isp_gen_set_pt, vfe_v4l2_isp(VFE_WB, ctrl->val, V4L2_TO_ISP));
			break;
		case V4L2_CID_WIDE_DYNAMIC_RANGE:
			bsp_isp_s_wide_dynamic_rage(dev->isp_gen_set_pt, ctrl->val);
			break;
		case V4L2_CID_IMAGE_STABILIZATION:
			bsp_isp_s_image_stabilization(dev->isp_gen_set_pt, ctrl->val);
			break;
		case V4L2_CID_ISO_SENSITIVITY:
			bsp_isp_s_iso_sensitivity(dev->isp_gen_set_pt, ctrl->qmenu_int[ctrl->val]);
			break;
		case V4L2_CID_ISO_SENSITIVITY_AUTO:
			bsp_isp_s_iso_sensitivity_auto(dev->isp_gen_set_pt, vfe_v4l2_isp(VFE_ISO, ctrl->val, V4L2_TO_ISP));
			break;
		case V4L2_CID_EXPOSURE_METERING:
			ret = -EINVAL;
			break;
		case V4L2_CID_SCENE_MODE:
			bsp_isp_s_scene_mode(dev->isp_gen_set_pt, vfe_v4l2_isp(VFE_SCENE, ctrl->val, V4L2_TO_ISP));
			break;
		case V4L2_CID_3A_LOCK:
			if (dev->ctrl_para.exp_auto_mode != V4L2_EXPOSURE_MANUAL) {
				if (IS_FLAG(ctrl->val, V4L2_LOCK_EXPOSURE))
					dev->isp_gen_set_pt->exp_settings.exposure_lock = ISP_TRUE;
				else
					dev->isp_gen_set_pt->exp_settings.exposure_lock = ISP_FALSE;
			}
			if (dev->ctrl_para.auto_wb == 1) {
				if (IS_FLAG(ctrl->val, V4L2_LOCK_WHITE_BALANCE))
					dev->isp_gen_set_pt->wb_settings.white_balance_lock = ISP_TRUE;
				else
					dev->isp_gen_set_pt->wb_settings.white_balance_lock = ISP_FALSE;
			}
			if (dev->ctrl_para.auto_focus == 1) {
				if (IS_FLAG(ctrl->val, V4L2_LOCK_FOCUS))
					dev->isp_gen_set_pt->af_settings.focus_lock = ISP_TRUE;
				else
					dev->isp_gen_set_pt->af_settings.focus_lock = ISP_FALSE;
			}
			break;
		case V4L2_CID_AUTO_FOCUS_START:
			dev->isp_3a_result_pt->af_status = AUTO_FOCUS_STATUS_REFOCUS;
			bsp_isp_s_auto_focus_start(dev->isp_gen_set_pt, ctrl->val);
			isp_s_ctrl_torch_open(dev);
			break;
		case V4L2_CID_AUTO_FOCUS_STOP:
			vfe_dbg(0, "V4L2_CID_AUTO_FOCUS_STOP\n");
			bsp_isp_s_auto_focus_stop(dev->isp_gen_set_pt, ctrl->val);
			isp_s_ctrl_torch_close(dev);
			break;
		case V4L2_CID_AUTO_FOCUS_RANGE:
			bsp_isp_s_auto_focus_range(dev->isp_gen_set_pt, vfe_v4l2_isp(VFE_AF_RANGE, ctrl->val, V4L2_TO_ISP));
			break;
		case V4L2_CID_FLASH_LED_MODE:
			bsp_isp_s_flash_mode(dev->isp_gen_set_pt, vfe_v4l2_isp(VFE_FLASH_MODE, ctrl->val, V4L2_TO_ISP));
			if (ctrl->val == V4L2_FLASH_LED_MODE_TORCH)
				io_set_flash_ctrl(dev->flash_sd, SW_CTRL_TORCH_ON);
			else if (ctrl->val == V4L2_FLASH_LED_MODE_NONE)
				io_set_flash_ctrl(dev->flash_sd, SW_CTRL_FLASH_OFF);
			break;
		case V4L2_CID_AUTO_FOCUS_INIT:
			break;
		case V4L2_CID_AUTO_FOCUS_RELEASE:
			break;
		case V4L2_CID_GSENSOR_ROTATION:
			bsp_isp_s_gsensor_rotation(dev->isp_gen_set_pt, ctrl->val);
			dev->ctrl_para.gsensor_rot = ctrl->val;
			break;
		case V4L2_CID_TAKE_PICTURE:
			bsp_isp_s_take_pic(dev->isp_gen_set_pt, ctrl->val);
			break;
		case V4L2_CID_R_GAIN:
			bsp_isp_s_r_gain(dev->isp_gen_set_pt, ctrl->val);
			break;
		case V4L2_CID_G_GAIN:
			bsp_isp_s_g_gain(dev->isp_gen_set_pt, ctrl->val);
			break;
		case V4L2_CID_B_GAIN:
			bsp_isp_s_b_gain(dev->isp_gen_set_pt, ctrl->val);
			break;
		case V4L2_CID_VFLIP:
			c.value = ctrl->val;
			ret = v4l2_s_ctrl(NULL, dev->sd->ctrl_handler, &c);
			break;
		case V4L2_CID_HFLIP:
			c.value = ctrl->val;
			ret = v4l2_s_ctrl(NULL, dev->sd->ctrl_handler, &c);
			break;
		default:
			ret = -EINVAL;
			break;
		}
		if (ret < 0)
			vfe_warn("v4l2 isp s_ctrl fail!\n");
	} else {
		switch (ctrl->id) {
		case V4L2_CID_FOCUS_ABSOLUTE:
			vcm_ctrl.code = ctrl->val;
			vcm_ctrl.sr = 0x0;
			ret = v4l2_subdev_call(dev->sd_act, core, ioctl, ACT_SET_CODE, &vcm_ctrl);
			break;
		case V4L2_CID_FLASH_LED_MODE:
			ret = v4l2_s_ctrl(NULL, dev->flash_sd->ctrl_handler, &c);
			break;
		case V4L2_CID_AUTO_FOCUS_START:
			sunxi_flash_check_to_start(dev->flash_sd, SW_CTRL_TORCH_ON);
			ret = v4l2_s_ctrl(NULL, dev->sd->ctrl_handler, &c);
			break;
		case V4L2_CID_AUTO_FOCUS_STOP:
			sunxi_flash_stop(dev->flash_sd);
			ret = v4l2_s_ctrl(NULL, dev->sd->ctrl_handler, &c);
			break;
		case V4L2_CID_AUTO_EXPOSURE_BIAS:
			c.value = ctrl->val;
			ret = v4l2_s_ctrl(NULL, dev->sd->ctrl_handler, &c);
			break;
		case V4L2_CID_VFLIP:
			c.value = ctrl->val;
			ret = v4l2_s_ctrl(NULL, dev->sd->ctrl_handler, &c);
			break;
		case V4L2_CID_HFLIP:
			c.value = ctrl->val;
			ret = v4l2_s_ctrl(NULL, dev->sd->ctrl_handler, &c);
			break;
		default:
			ret = v4l2_s_ctrl(NULL, dev->sd->ctrl_handler, &c);
			break;
		}
		if (ret < 0)
			vfe_warn("v4l2 sensor s_ctrl fail!\n");
	}
	return ret;
}
#ifdef CONFIG_COMPAT
struct isp_stat_buf32 {
	compat_caddr_t buf;
	__u32 buf_size;
};

static int get_isp_stat_buf32(struct isp_stat_buf *kp, struct isp_stat_buf32 __user *up)
{
	u32 tmp;

	if (!access_ok(VERIFY_READ, up, sizeof(struct isp_stat_buf32)) ||
		get_user(kp->buf_size, &up->buf_size) ||
		get_user(tmp, &up->buf))
			return -EFAULT;
	kp->buf = compat_ptr(tmp);

	return 0;
}

static int put_isp_stat_buf32(struct isp_stat_buf *kp, struct isp_stat_buf32 __user *up)
{
	u32 tmp = (u32)((unsigned long)kp->buf);

	if (!access_ok(VERIFY_WRITE, up, sizeof(struct isp_stat_buf32)) ||
		put_user(kp->buf_size, &up->buf_size) ||
		put_user(tmp, &up->buf))
			return -EFAULT;

	return 0;
}

#define VIDIOC_ISP_AE_STAT_REQ32	_IOWR('V', BASE_VIDIOC_PRIVATE + 1, struct isp_stat_buf32)
#define VIDIOC_ISP_HIST_STAT_REQ32	_IOWR('V', BASE_VIDIOC_PRIVATE + 2, struct isp_stat_buf32)
#define VIDIOC_ISP_AF_STAT_REQ32	_IOWR('V', BASE_VIDIOC_PRIVATE + 3, struct isp_stat_buf32)
#define VIDIOC_ISP_GAMMA_REQ32	_IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct isp_stat_buf32)

static long vfe_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
{
	union {
		struct isp_stat_buf isb;
	} karg;
	void __user *up = compat_ptr(arg);
	int compatible_arg = 1;
	long err = 0;

	switch (cmd) {
	case VIDIOC_ISP_AE_STAT_REQ32:
		cmd = VIDIOC_ISP_AE_STAT_REQ;
		break;
	case VIDIOC_ISP_HIST_STAT_REQ32:
		cmd = VIDIOC_ISP_HIST_STAT_REQ;
		break;
	case VIDIOC_ISP_AF_STAT_REQ32:
		cmd = VIDIOC_ISP_AF_STAT_REQ;
		break;
	case VIDIOC_ISP_GAMMA_REQ32:
		cmd = VIDIOC_ISP_GAMMA_REQ;
		break;
	}
	switch (cmd) {
	case VIDIOC_ISP_AE_STAT_REQ:
	case VIDIOC_ISP_HIST_STAT_REQ:
	case VIDIOC_ISP_AF_STAT_REQ:
	case VIDIOC_ISP_GAMMA_REQ:
		err = get_isp_stat_buf32(&karg.isb, up);
		compatible_arg = 0;
		break;
	}
	if (err)
		return err;
	if (compatible_arg)
		err = video_ioctl2(file, cmd, (unsigned long)up);
	else {
		mm_segment_t old_fs = get_fs();

		set_fs(KERNEL_DS);
		if (file->f_op->unlocked_ioctl)
			err = file->f_op->unlocked_ioctl(file, cmd, (unsigned long)&karg);
		else
			err = -ENOIOCTLCMD;
		set_fs(old_fs);
	}
	switch (cmd) {
	case VIDIOC_ISP_AE_STAT_REQ:
	case VIDIOC_ISP_HIST_STAT_REQ:
	case VIDIOC_ISP_AF_STAT_REQ:
	case VIDIOC_ISP_GAMMA_REQ:
		if (put_isp_stat_buf32(&karg.isb, up))
			err = -EFAULT;
		break;
	}
	return err;
}
#endif

int vfe_open_special(int id)
{
	struct vfe_dev *dev = vfe_dev_gbl[id];
	struct vfe_dmaqueue *active = &dev->vidq_special;
	struct vfe_dmaqueue *done = &dev->done_special;

	INIT_LIST_HEAD(&active->active);
	INIT_LIST_HEAD(&done->active);
	dev->special_active = 1;

	return __vfe_open(dev);
}
EXPORT_SYMBOL(vfe_open_special);

int vfe_s_input_special(int id, int sel)
{
	struct vfe_dev *dev = vfe_dev_gbl[id];

	return internal_s_input(dev, sel);
}
EXPORT_SYMBOL(vfe_s_input_special);

int vfe_close_special(int id)
{
	struct vfe_dev *dev = vfe_dev_gbl[id];
	struct vfe_dmaqueue *active = &dev->vidq_special;
	struct vfe_dmaqueue *done = &dev->done_special;

	INIT_LIST_HEAD(&active->active);
	INIT_LIST_HEAD(&done->active);
	dev->special_active = 0;

	return __vfe_close(dev);
}
EXPORT_SYMBOL(vfe_close_special);

int vfe_s_fmt_special(int id, struct v4l2_format *f)
{
	struct vfe_dev *dev = vfe_dev_gbl[id];

	return s_fmt_internal(dev, NULL, f);
}
EXPORT_SYMBOL(vfe_s_fmt_special);

int vfe_g_fmt_special(int id, struct v4l2_format *f)
{
	struct vfe_dev *dev = vfe_dev_gbl[id];

	f->fmt.pix.width        = dev->width;
	f->fmt.pix.height       = dev->height;
	f->fmt.pix.field	= dev->fmt.field;
	f->fmt.pix.pixelformat  = dev->fmt.bus_pix_code;

	return 0;
}
EXPORT_SYMBOL(vfe_g_fmt_special);

void os_mem_free_sample(int id, struct vfe_mm *mem_man)
{
	struct vfe_dev *dev = vfe_dev_gbl[id];
	struct device pdev = dev->pdev->dev;

	os_mem_free(&pdev, mem_man);
}
EXPORT_SYMBOL(os_mem_free_sample);

int os_mem_alloc_sample(int id, struct vfe_mm *mem_man)
{
	struct vfe_dev *dev = vfe_dev_gbl[id];
	struct device pdev = dev->pdev->dev;

	return os_mem_alloc(&pdev, mem_man);
}
EXPORT_SYMBOL(os_mem_alloc_sample);

int vfe_dqbuffer_special(int id, struct vfe_buffer **buf)
{
	int ret = 0;
	unsigned long flags = 0;
	struct vfe_dev *dev = vfe_dev_gbl[id];
	struct vfe_dmaqueue *done = &dev->done_special;

	spin_lock_irqsave(&dev->slock, flags);
	if (!list_empty(&done->active)) {
		*buf = list_first_entry(&done->active, struct vfe_buffer, list);
		list_del(&((*buf)->list));
		(*buf)->state = VB2_BUF_STATE_DEQUEUED;
	} else {
		vfe_err("there is no done buf, please wait\n");
		ret = -1;
	}
	spin_unlock_irqrestore(&dev->slock, flags);

	return ret;
}
EXPORT_SYMBOL(vfe_dqbuffer_special);

int vfe_qbuffer_special(int id, struct vfe_buffer *buf)
{
	struct vfe_dev *dev = vfe_dev_gbl[id];
	struct vfe_dmaqueue *vidq = &dev->vidq_special;
	unsigned long flags = 0;

	if (buf == NULL) {
		vfe_err("buf is NULL, cannot qbuf\n");
		return -1;
	}

	spin_lock_irqsave(&dev->slock, flags);
	list_add_tail(&buf->list, &vidq->active);
	buf->state = VB2_BUF_STATE_QUEUED;
	spin_unlock_irqrestore(&dev->slock, flags);

	return 0;
}
EXPORT_SYMBOL(vfe_qbuffer_special);

int vfe_streamon_special(int id, enum v4l2_buf_type i)
{
	struct vfe_dev *dev = vfe_dev_gbl[id];

	return __vfe_streamon(dev, NULL, i);
}
EXPORT_SYMBOL(vfe_streamon_special);

int vfe_streamoff_special(int id, enum v4l2_buf_type i)
{
	struct vfe_dev *dev = vfe_dev_gbl[id];

	return __vfe_streamoff(dev, NULL, i);
}
EXPORT_SYMBOL(vfe_streamoff_special);

void vfe_register_buffer_done_callback(int id, void *func)
{
	struct vfe_dev *dev = vfe_dev_gbl[id];

	dev->vfe_buffer_process = func;
}
EXPORT_SYMBOL(vfe_register_buffer_done_callback);

/* ------------------------------------------------------------------ */
/*	File operations for the device  */
/*   ------------------------------------------------------------------*/

static const struct v4l2_ctrl_ops vfe_ctrl_ops = {
	.g_volatile_ctrl = vfe_g_volatile_ctrl,
	.s_ctrl = vfe_s_ctrl,
};

static const struct v4l2_file_operations vfe_fops = {
	.owner          = THIS_MODULE,
	.open           = vfe_open,
	.release        = vfe_close,
	.read           = vfe_read,
	.poll           = vfe_poll,
	.unlocked_ioctl = video_ioctl2,
#ifdef CONFIG_COMPAT
	.compat_ioctl32 = vfe_compat_ioctl32,
#endif
	.mmap           = vfe_mmap,
};

static const struct v4l2_ioctl_ops vfe_ioctl_ops = {
	.vidioc_querycap          = vidioc_querycap,
	.vidioc_enum_fmt_vid_cap  = vidioc_enum_fmt_vid_cap,
	.vidioc_enum_framesizes   = vidioc_enum_framesizes,
	.vidioc_g_fmt_vid_cap     = vidioc_g_fmt_vid_cap,
	.vidioc_try_fmt_vid_cap   = vidioc_try_fmt_vid_cap,
	.vidioc_s_fmt_vid_cap     = vidioc_s_fmt_vid_cap,
	.vidioc_reqbufs           = vidioc_reqbufs,
	.vidioc_querybuf          = vidioc_querybuf,
	.vidioc_qbuf              = vidioc_qbuf,
	.vidioc_dqbuf             = vidioc_dqbuf,
	.vidioc_enum_input        = vidioc_enum_input,
	.vidioc_g_input           = vidioc_g_input,
	.vidioc_s_input           = vidioc_s_input,
	.vidioc_streamon          = vidioc_streamon,
	.vidioc_streamoff         = vidioc_streamoff,
	.vidioc_g_parm            = vidioc_g_parm,
	.vidioc_s_parm            = vidioc_s_parm,
	.vidioc_default		 = vfe_param_handler,
};

static struct video_device vfe_template[] = {

	[0] = {
		.name       = "vfe_0",
		.fops       = &vfe_fops,
		.ioctl_ops  = &vfe_ioctl_ops,
		.release    = video_device_release,
	},
	[1] = {
		.name       = "vfe_1",
		.fops       = &vfe_fops,
		.ioctl_ops  = &vfe_ioctl_ops,
		.release    = video_device_release,
	},
};

static int vfe_pin_config(struct vfe_dev *dev, int enable)
{
	char pinctrl_names[10] = "";
#ifdef VFE_GPIO
	if (!IS_ERR_OR_NULL(dev->pctrl))
		devm_pinctrl_put(dev->pctrl);

	if (enable == 1)
		strcpy(pinctrl_names, "default");
	else
		strcpy(pinctrl_names, "sleep");

	dev->pctrl = devm_pinctrl_get_select(&dev->pdev->dev, pinctrl_names);
	if (IS_ERR_OR_NULL(dev->pctrl))
		vfe_err("vip%d request pinctrl handle for device [%s] failed!\n", dev->id, dev_name(&dev->pdev->dev));
		return -EINVAL;

	usleep_range(5000, 6000);
#else
	void __iomem *gpio_base;

	vfe_print("directly write pin config @ FPGA\n");
	gpio_base = ioremap(GPIO_REGS_VBASE, 0x120);
	if (!gpio_base) {
		pr_info("gpio_base directly write pin config EIO\n");
		return -EIO;
	}
#ifdef FPGA_PIN	/* Direct write for pin of FPGA */
	writel(0x33333333, (gpio_base+0x90));
	writel(0x33333333, (gpio_base+0x94));
	writel(0x03333333, (gpio_base+0x98));
#else /* Direct write for pin of IC */
	writel(0x22222222, (gpio_base+0x90));
	writel(0x10222222, (gpio_base+0x94));
	writel(0x11111111, (gpio_base+0x98));
#endif
#endif

	return 0;
}

static int vfe_pin_release(struct vfe_dev *dev)
{
#ifdef VFE_GPIO
	if (!IS_ERR_OR_NULL(dev->pctrl))
		devm_pinctrl_put(dev->pctrl);
#endif
	return 0;
}

static int vfe_request_gpio(struct vfe_dev *dev)
{
#ifdef VFE_GPIO
	unsigned int i, j;

	for (i = 0; i < dev->dev_qty; i++) {
		for (j = 0; j < MAX_GPIO_NUM; j++) {
			os_gpio_request(&dev->ccm_cfg[i]->gpio[j], 1);
			/* os_gpio_set(&dev->ccm_cfg[i]->gpio[j],1); */
		}
	}
#endif
	return 0;
}

static int vfe_gpio_config(struct vfe_dev *dev, int bon)
{
#ifdef VFE_GPIO
	unsigned int i, j;
	struct vfe_gpio_cfg gpio_item;

	for (i = 0; i < dev->dev_qty; i++) {
		for (j = 0; j < MAX_GPIO_NUM; j++) {
			memcpy(&gpio_item, &dev->ccm_cfg[i]->gpio[j], sizeof(struct vfe_gpio_cfg));
			if (bon == 0)
				gpio_item.mul_sel = GPIO_DISABLE;
			os_gpio_set(&gpio_item, 1);
		}
	}
#endif
	return 0;
}

static void vfe_gpio_release(struct vfe_dev *dev)
{
#ifdef VFE_GPIO
	unsigned int i, j;

	for (i = 0; i < dev->dev_qty; i++) {
		for (j = 0; j < MAX_GPIO_NUM; j++)
			os_gpio_release(dev->ccm_cfg[i]->gpio[j].gpio, 1);
	}
#endif
}

static int vfe_resource_request(struct platform_device *pdev, struct vfe_dev *dev)
{
	int ret;
	struct device_node *np = pdev->dev.of_node;

	vfe_dbg(0, "get irq resource\n");
	/*get irq resource*/
	dev->irq = irq_of_parse_and_map(np, 0);
	if (dev->irq <= 0) {
		vfe_err("failed to get IRQ resource\n");
		return -ENXIO;
	}

#define INTC_EN_IRQ1			(0xf1c20400 + 0x24)
#define INTC_PEND_REG1		    (0xf1c20400 + 0x14)
#define INTC_FF_REG1		    (0xf1c20400 + 0x54)

#define CSI_BASE_REG			 0xf1cb0000
#define CSI_IRQ_EN			    (0xf1cb0000 + 0x30)
#define CSI_IRQ_ST			    (0xf1cb0000 + 0x34)

#define IRQ_EN	(1<<0)
#ifdef CONFIG_ARCH_SUN3IW1P1
	ret = request_irq(dev->irq, vfe_isr, 0, "csi_irq", dev);
	if (ret) {
				vfe_err("failed to install irq (%d)\n", ret);
				return -ENXIO;
	}
	writel(CSI_INT_ALL, CSI_IRQ_EN);
	writel(0xff, CSI_BASE_REG);

	pr_info("%s: csi irq(%d) enable\n", __func__, dev->irq);
#else
#ifndef FPGA_VER
	ret = request_irq(dev->irq, vfe_isr, IRQF_SHARED, pdev->name, dev);
#else
	ret = request_irq(dev->irq, vfe_isr, IRQF_SHARED, pdev->name, dev);
#endif
	if (ret) {
		vfe_err("failed to install irq (%d)\n", ret);
		return -ENXIO;
	}
	vfe_dbg(0, "clock resource\n");
#endif

	vfe_dbg(0, "get pin resource\n");
	/* request gpio */
	vfe_request_gpio(dev);

	return 0;
}

static void vfe_resource_release(struct vfe_dev *dev)
{
	vfe_gpio_release(dev);
	vfe_pin_release(dev);
	/* vfe_clk_release(dev); */
	if (dev->irq > 0)
		free_irq(dev->irq, dev);
}
static int vfe_set_sensor_power_on(struct vfe_dev *dev)
{
	int ret = 0;
#ifdef _REGULATOR_CHANGE_
	vfe_device_regulator_get(&dev->pdev->dev, dev->ccm_cfg[dev->input], dev->input);
	dev->power = &dev->ccm_cfg[dev->input]->power;
#endif

#if defined(CONFIG_ARCH_SUN8IW6P1) || defined(CONFIG_ARCH_SUN8IW7P1)
#else
	if (!IS_ERR_OR_NULL(dev->sd))
		vfe_set_pmu_channel(dev->sd, IOVDD, ON);

	usleep_range(10000, 12000);
#endif
	ret = v4l2_subdev_call(dev->sd, core, s_power, CSI_SUBDEV_PWR_ON);
	dev->vfe_sensor_power_cnt++;
	vfe_dbg(0, "power_on______________________________\n");
	return ret;
}

static int vfe_set_sensor_power_off(struct vfe_dev *dev)
{
	int ret = 0;

	if (dev->vfe_sensor_power_cnt > 0) {
		ret = v4l2_subdev_call(dev->sd, core, s_power, CSI_SUBDEV_PWR_OFF);
#if defined(CONFIG_ARCH_SUN8IW6P1) || defined(CONFIG_ARCH_SUN8IW7P1)
#else
		usleep_range(10000, 12000);
		if (!IS_ERR_OR_NULL(dev->sd))
			vfe_set_pmu_channel(dev->sd, IOVDD, OFF);
#endif
		dev->vfe_sensor_power_cnt--;
	} else {
		vfe_warn("Sensor is already power off!\n");
		dev->vfe_sensor_power_cnt = 0;
	}

#ifdef _REGULATOR_CHANGE_
	vfe_device_regulator_put(dev->ccm_cfg[dev->input]);
#endif
	vfe_dbg(0, "power_off______________________________\n");

	return ret;
}

static const char *vfe_regulator_name[] = {
	VFE_ISP_REGULATOR,
	VFE_CSI_REGULATOR,
};

static int vfe_get_regulator(struct vfe_dev *dev)
{
	struct regulator *regul;
	unsigned int i;

	for (i = 0; i < ARRAY_SIZE(vfe_regulator_name); ++i) {
		if (strcmp(vfe_regulator_name[i], "") != 0) {
			regul = regulator_get(NULL, vfe_regulator_name[i]);
			if (IS_ERR_OR_NULL(regul)) {
				vfe_err("get regulator vfe system power error, i = %d!\n", i);
				regul = NULL;
			}
		} else
			regul = NULL;

		dev->vfe_system_power[i] = regul;
	}

	return 0;
}
static int vfe_enable_regulator_all(struct vfe_dev *dev)
{
	unsigned int i, ret = -1;

	for (i = 0; i < ARRAY_SIZE(vfe_regulator_name); ++i) {
		if (dev->vfe_system_power[i] != NULL)
			ret = regulator_enable(dev->vfe_system_power[i]);
	}
	usleep_range(5000, 6000);

	return ret;
}

static int vfe_disable_regulator_all(struct vfe_dev *dev)
{
	unsigned int i, ret = -1;

	for (i = 0; i < ARRAY_SIZE(vfe_regulator_name); ++i) {
		if (dev->vfe_system_power[i] != NULL)
			ret = regulator_disable(dev->vfe_system_power[i]);
	}

	return ret;
}

static int vfe_put_regulator(struct vfe_dev *dev)
{
	unsigned int i;

	for (i = 0; i < ARRAY_SIZE(vfe_regulator_name); ++i) {
		if (dev->vfe_system_power[i] != NULL)
			regulator_put(dev->vfe_system_power[i]);
	}

	return 0;
}

static int vfe_device_regulator_get(struct device *dev, struct ccm_config *ccm_cfg, int num)
{
#ifdef VFE_PMU
	struct platform_device *pdev;
	pdev = container_of(dev, struct platform_device, dev);
	/*power issue*/
	ccm_cfg->power.iovdd = NULL;
	ccm_cfg->power.avdd = NULL;
	ccm_cfg->power.dvdd = NULL;
	ccm_cfg->power.afvdd = NULL;
	ccm_cfg->power.flvdd = NULL;

	snprintf(ccm_cfg->iovdd_str, sizeof(ccm_cfg->iovdd_str), "csi%d_dev%d_iovdd", pdev->id, num);
	if (strcmp(ccm_cfg->iovdd_str, "")) {
		ccm_cfg->power.iovdd = regulator_get(dev, ccm_cfg->iovdd_str);
		if (IS_ERR_OR_NULL(ccm_cfg->power.iovdd)) {
			vfe_err("get regulator csi_iovdd error!\n");
			goto regulator_get_err;
		}
	}
	snprintf(ccm_cfg->avdd_str, sizeof(ccm_cfg->avdd_str), "csi%d_dev%d_avdd", pdev->id, num);
	if (strcmp(ccm_cfg->avdd_str, "")) {
		ccm_cfg->power.avdd = regulator_get(dev, ccm_cfg->avdd_str);
		if (IS_ERR_OR_NULL(ccm_cfg->power.avdd)) {
			vfe_err("get regulator csi_avdd error!\n");
			goto regulator_get_err;
		}
	}
	snprintf(ccm_cfg->dvdd_str, sizeof(ccm_cfg->dvdd_str), "csi%d_dev%d_dvdd", pdev->id, num);
	if (strcmp(ccm_cfg->dvdd_str, "")) {
		ccm_cfg->power.dvdd = regulator_get(dev, ccm_cfg->dvdd_str);
		if (IS_ERR_OR_NULL(ccm_cfg->power.dvdd)) {
			vfe_err("get regulator csi_dvdd error!\n");
			goto regulator_get_err;
		}
	}
	snprintf(ccm_cfg->afvdd_str, sizeof(ccm_cfg->afvdd_str), "csi%d_dev%d_afvdd", pdev->id, num);
	if (strcmp(ccm_cfg->afvdd_str, "")) {
		ccm_cfg->power.afvdd = regulator_get(dev, ccm_cfg->afvdd_str);
		if (IS_ERR_OR_NULL(ccm_cfg->power.afvdd)) {
			vfe_err("get regulator csi_afvdd error!\n");
			goto regulator_get_err;
		}
	}
	snprintf(ccm_cfg->flvdd_str, sizeof(ccm_cfg->flvdd_str), "csi%d_dev%d_flvdd", pdev->id, num);
	if (strcmp(ccm_cfg->flvdd_str, "")) {
		ccm_cfg->power.flvdd = regulator_get(dev, ccm_cfg->flvdd_str);
		if (IS_ERR_OR_NULL(ccm_cfg->power.flvdd)) {
			vfe_err("get regulator csi_flvdd error!\n");
			goto regulator_get_err;
		}
	}

	return 0;
regulator_get_err:
	return -1;
#else
	return 0;
#endif
}

static int vfe_device_regulator_put(struct ccm_config  *ccm_cfg)
{
	/*power issue*/
	if (!IS_ERR_OR_NULL(ccm_cfg->power.iovdd))
		regulator_put(ccm_cfg->power.iovdd);
	if (!IS_ERR_OR_NULL(ccm_cfg->power.avdd))
		regulator_put(ccm_cfg->power.avdd);
	if (!IS_ERR_OR_NULL(ccm_cfg->power.dvdd))
		regulator_put(ccm_cfg->power.dvdd);
	if (!IS_ERR_OR_NULL(ccm_cfg->power.afvdd))
		regulator_put(ccm_cfg->power.afvdd);
	if (!IS_ERR_OR_NULL(ccm_cfg->power.flvdd))
		regulator_put(ccm_cfg->power.flvdd);

	return 0;
}

static int vfe_sensor_check(struct vfe_dev *dev)
{
	int ret = 0;
	struct v4l2_subdev *sd = dev->sd;

	vfe_print("Check sensor!\n");
	vfe_set_sensor_power_on(dev);
#ifdef USE_SPECIFIC_CCI
	csi_cci_init_helper(dev->cci_sel);
#endif
	ret = (v4l2_subdev_call(sd, core, init, 0) < 0) ? -1 : 0;
	vfe_set_sensor_power_off(dev);
	if (vfe_i2c_dbg == 1) {
		vfe_print("NOTE: Sensor i2c dbg, it's always power on and register success!..................\n");
		ret = 0;
		vfe_set_sensor_power_on(dev);
	}
#ifdef USE_SPECIFIC_CCI
	csi_cci_exit_helper(dev->cci_sel);
#endif
	return ret;
}

#ifdef USE_SPECIFIC_CCI
static int vfe_sensor_subdev_register_check(struct vfe_dev *dev,
					struct v4l2_device *v4l2_dev,
					struct ccm_config  *ccm_cfg,
					struct i2c_board_info *sensor_i2c_board)
{
	int ret;

	ccm_cfg->sd = NULL;
	ccm_cfg->sd = cci_bus_match(ccm_cfg->ccm, dev->cci_sel, sensor_i2c_board->addr);/* ccm_cfg->i2c_addr >> 1);*/
	if (ccm_cfg->sd) {
		ret = v4l2_device_register_subdev(&dev->v4l2_dev, ccm_cfg->sd);
		vfe_print("v4l2_device_register_subdev return %d\n", ret);
		if (ret < 0)
			ccm_cfg->sd = NULL;
	}
	update_ccm_info(dev, ccm_cfg);
	if (IS_ERR_OR_NULL(ccm_cfg->sd)) {
		vfe_err("Error registering v4l2 subdevice No such device!\n");
		return -ENODEV;
	} else
		vfe_print("registered sensor subdev is OK!\n");
	/* Subdev register is OK, check sensor init! */
	return vfe_sensor_check(dev);
}

static int vfe_sensor_subdev_unregister(struct v4l2_device *v4l2_dev,
					struct ccm_config  *ccm_cfg,
					struct i2c_board_info *sensor_i2c_board)
{
	struct cci_driver *cci_driv = v4l2_get_subdevdata(ccm_cfg->sd);

	if (IS_ERR_OR_NULL(cci_driv))
		return -ENODEV;
	vfe_print("vfe sensor subdev unregister!\n");
	v4l2_device_unregister_subdev(ccm_cfg->sd);
	cci_bus_match_cancel(cci_driv);

	return 0;
}
static int vfe_actuator_subdev_register(struct vfe_dev *dev,
					struct ccm_config  *ccm_cfg,
					struct i2c_board_info *act_i2c_board)
{
	ccm_cfg->sd_act = NULL;
	ccm_cfg->sd_act = cci_bus_match(ccm_cfg->act_name, dev->cci_sel, act_i2c_board->addr);/* ccm_cfg->i2c_addr >> 1); */
	/* reg_sd_act: */
	if (!ccm_cfg->sd_act) {
		vfe_err("Error registering v4l2 act subdevice!\n");
		return  -EINVAL;
	} else
		vfe_print("registered actuator device succeed! act_name is %s\n", ccm_cfg->act_name);

	ccm_cfg->act_ctrl = (struct actuator_ctrl_t *)container_of(ccm_cfg->sd_act, struct actuator_ctrl_t, sdev);
	/* pr_info("ccm_cfg->act_ctrl=%x\n",(unsigned int )ccm_cfg->act_ctrl); */

	return 0;
}
#else /* NOT defind USE_SPECIFIC_CCI */
static int vfe_sensor_subdev_register_check(struct vfe_dev *dev,
					struct v4l2_device *v4l2_dev,
					struct ccm_config  *ccm_cfg,
					struct i2c_board_info *sensor_i2c_board)
{
	struct i2c_adapter *i2c_adap = i2c_get_adapter(ccm_cfg->twi_id);

	if (i2c_adap == NULL) {
		vfe_err("request i2c adapter failed!\n");
		return -EFAULT;
	}
	ccm_cfg->sd = v4l2_i2c_new_subdev_board(v4l2_dev, i2c_adap, sensor_i2c_board, NULL);
	if (IS_ERR_OR_NULL(ccm_cfg->sd)) {
		i2c_put_adapter(i2c_adap);
		vfe_err("Error registering v4l2 subdevice No such device!\n");
		return -ENODEV;
	} else
		vfe_print("registered sensor subdev is OK!\n");

	update_ccm_info(dev, ccm_cfg);
	/* Subdev register is OK, check sensor init! */
	return vfe_sensor_check(dev);
}
static int vfe_sensor_subdev_unregister(struct v4l2_device *v4l2_dev,
					struct ccm_config  *ccm_cfg,
					struct i2c_board_info *sensor_i2c_board)
{
	struct i2c_client *client = v4l2_get_subdevdata(ccm_cfg->sd);
	struct i2c_adapter *adapter;

	if (!client)
		return -ENODEV;
	vfe_print("vfe sensor subdev unregister!\n");
	v4l2_device_unregister_subdev(ccm_cfg->sd);
	adapter = client->adapter;
	i2c_unregister_device(client);
	if (adapter)
		i2c_put_adapter(adapter);

	return 0;
}
static int vfe_actuator_subdev_register(struct vfe_dev *dev,
					struct ccm_config  *ccm_cfg,
					struct i2c_board_info *act_i2c_board)
{
	struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
	struct i2c_adapter *i2c_adap_act = i2c_get_adapter(ccm_cfg->twi_id);/* must use the same twi_channel with sensor */

	if (i2c_adap_act == NULL) {
		vfe_err("request act i2c adapter failed\n");
		return  -EINVAL;
	}

	ccm_cfg->sd_act = NULL;
	act_i2c_board->addr = (unsigned short)(ccm_cfg->act_slave>>1);
	strcpy(act_i2c_board->type, ccm_cfg->act_name);
	ccm_cfg->sd_act = v4l2_i2c_new_subdev_board(v4l2_dev, i2c_adap_act, act_i2c_board, NULL);
	/* reg_sd_act: */
	if (!ccm_cfg->sd_act) {
		vfe_err("Error registering v4l2 act subdevice!\n");
		return  -EINVAL;
	} else
		vfe_print("registered actuator device succeed!\n");

	ccm_cfg->act_ctrl = (struct actuator_ctrl_t *)container_of(ccm_cfg->sd_act, struct actuator_ctrl_t, sdev);

	return 0;
}
#endif
static void cpy_ccm_power_settings(struct ccm_config *ccm_cfg)
{
	strcpy(ccm_cfg->iovdd_str, ccm_cfg->sensor_cfg_ini->sub_power_str[ENUM_IOVDD]);
	ccm_cfg->power.iovdd_vol = ccm_cfg->sensor_cfg_ini->sub_power_vol[ENUM_IOVDD];

	strcpy(ccm_cfg->avdd_str, ccm_cfg->sensor_cfg_ini->sub_power_str[ENUM_AVDD]);
	ccm_cfg->power.avdd_vol = ccm_cfg->sensor_cfg_ini->sub_power_vol[ENUM_AVDD];

	strcpy(ccm_cfg->dvdd_str, ccm_cfg->sensor_cfg_ini->sub_power_str[ENUM_DVDD]);
	ccm_cfg->power.dvdd_vol = ccm_cfg->sensor_cfg_ini->sub_power_vol[ENUM_DVDD];

	strcpy(ccm_cfg->afvdd_str, ccm_cfg->sensor_cfg_ini->sub_power_str[ENUM_AFVDD]);
	ccm_cfg->power.afvdd_vol = ccm_cfg->sensor_cfg_ini->sub_power_vol[ENUM_AFVDD];
}

static int cpy_ccm_sub_device_cfg(struct ccm_config *ccm_cfg, int n)
{
	strcpy(ccm_cfg->ccm, ccm_cfg->sensor_cfg_ini->camera_inst[n].name);
	if (strcmp(ccm_cfg->sensor_cfg_ini->camera_inst[n].isp_cfg_name, ""))
		strcpy(ccm_cfg->isp_cfg_name, ccm_cfg->sensor_cfg_ini->camera_inst[n].isp_cfg_name);
	else
		strcpy(ccm_cfg->isp_cfg_name, ccm_cfg->ccm);

	ccm_cfg->i2c_addr = ccm_cfg->sensor_cfg_ini->camera_inst[n].i2c_addr;
	ccm_cfg->hflip = ccm_cfg->sensor_cfg_ini->camera_inst[n].hflip;
	ccm_cfg->vflip = ccm_cfg->sensor_cfg_ini->camera_inst[n].vflip;
	ccm_cfg->hflip_thumb = ccm_cfg->sensor_cfg_ini->camera_inst[n].hflip;
	ccm_cfg->vflip_thumb = ccm_cfg->sensor_cfg_ini->camera_inst[n].vflip;
	ccm_cfg->power.stby_mode = ccm_cfg->sensor_cfg_ini->camera_inst[n].stdby_mode;
	if (ccm_cfg->sensor_cfg_ini->camera_inst[n].sensor_type == SENSOR_RAW) {
		ccm_cfg->is_bayer_raw = 1;
		ccm_cfg->is_isp_used = 1;
	} else if (ccm_cfg->sensor_cfg_ini->camera_inst[n].sensor_type == SENSOR_YUV) {
		ccm_cfg->is_bayer_raw = 0;
		ccm_cfg->is_isp_used = 0;
	} else {
		ccm_cfg->is_bayer_raw = 0;
		ccm_cfg->is_isp_used = 1;
	}
	strcpy(ccm_cfg->act_name, ccm_cfg->sensor_cfg_ini->camera_inst[n].act_name);
	if (strcmp(ccm_cfg->act_name, "")) {
		ccm_cfg->act_used = 1;
		vfe_print("VCM driver name is \"%s\".\n", ccm_cfg->act_name);
	}
	ccm_cfg->act_slave = ccm_cfg->sensor_cfg_ini->camera_inst[n].act_i2c_addr;

	return 0;
}

static const char * const sensor_info_type[] = {
	"YUV",
	"RAW",
	NULL,
};

static struct v4l2_subdev *vfe_sensor_register_check(struct vfe_dev *dev,
						struct v4l2_device *v4l2_dev,
						struct ccm_config  *ccm_cfg,
						struct i2c_board_info *sensor_i2c_board,
						int input_num)
{
	int sensor_cnt, ret, sensor_num;
	struct sensor_item sensor_info;

	if (dev->vip_define_sensor_list == 1) {
		sensor_num = ccm_cfg->sensor_cfg_ini->detect_sensor_num;
		if (ccm_cfg->sensor_cfg_ini->detect_sensor_num == 0)
			sensor_num = 1;
	} else
		sensor_num = 1;

	for (sensor_cnt = 0; sensor_cnt < sensor_num; sensor_cnt++) {
		if (dev->vip_define_sensor_list == 1) {
			if (ccm_cfg->sensor_cfg_ini->detect_sensor_num > 0)
				cpy_ccm_sub_device_cfg(ccm_cfg, sensor_cnt);
		}
		if (get_sensor_info(ccm_cfg->ccm, &sensor_info) == 0) {
			if (ccm_cfg->i2c_addr != sensor_info.i2c_addr)
				vfe_warn("Sensor info \"%s\" i2c_addr is different from sys_config!\n", sensor_info.sensor_name);

			if (ccm_cfg->is_bayer_raw != sensor_info.sensor_type) {
				vfe_warn("Camer detect \"%s\" fmt is different from sys_config!\n",
								sensor_info_type[sensor_info.sensor_type]);
				vfe_warn("Apply detect  fmt = %d replace sys_config fmt = %d!\n",
								sensor_info.sensor_type, ccm_cfg->is_bayer_raw);
				ccm_cfg->is_bayer_raw = sensor_info.sensor_type;
			}
			if (sensor_info.sensor_type == SENSOR_RAW)
				ccm_cfg->is_isp_used = 1;

			else
				ccm_cfg->act_used = 0;

			vfe_print("Find sensor name is \"%s\", i2c address is %x, type is \"%s\" !\n",
								sensor_info.sensor_name, sensor_info.i2c_addr,
								sensor_info_type[sensor_info.sensor_type]);
		}
		sensor_i2c_board->addr = (unsigned short)(ccm_cfg->i2c_addr>>1);
		strcpy(sensor_i2c_board->type, ccm_cfg->ccm);

		vfe_print("Sub device register \"%s\" i2c_addr = 0x%x start!\n", sensor_i2c_board->type, ccm_cfg->i2c_addr);
		ret = vfe_sensor_subdev_register_check(dev, v4l2_dev, ccm_cfg, sensor_i2c_board);
		if (ret == -1) {
			vfe_sensor_subdev_unregister(v4l2_dev, ccm_cfg, sensor_i2c_board);
			vfe_print("Sub device register \"%s\" failed!\n", sensor_i2c_board->type);
			ccm_cfg->sd = NULL;
			continue;
		} else if (ret == ENODEV || ret == EFAULT)
			continue;
		else if (ret == 0) {
			vfe_print("Sub device register \"%s\" is OK!\n", sensor_i2c_board->type);
			break;
		}
	}
	return ccm_cfg->sd;
}

static const struct v4l2_ctrl_config custom_ctrls[] = {
	{
		.ops = &vfe_ctrl_ops,
		.id = V4L2_CID_HOR_VISUAL_ANGLE,
		.name = "Horizontal Visual Angle",
		.type = V4L2_CTRL_TYPE_INTEGER,
		.min = 0,
		.max = 360,
		.step = 1,
		.def = 60,
		.flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
	},
	{
		.ops = &vfe_ctrl_ops,
		.id = V4L2_CID_VER_VISUAL_ANGLE,
		.name = "Vertical Visual Angle",
		.type = V4L2_CTRL_TYPE_INTEGER,
		.min = 0,
		.max = 360,
		.step = 1,
		.def = 60,
		.flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
	},
	{
		.ops = &vfe_ctrl_ops,
		.id = V4L2_CID_FOCUS_LENGTH,
		.name = "Focus Length",
		.type = V4L2_CTRL_TYPE_INTEGER,
		.min = 0,
		.max = 1000,
		.step = 1,
		.def = 280,
		.flags = V4L2_CTRL_FLAG_VOLATILE,
	},
	{
		.ops = &vfe_ctrl_ops,
		.id = V4L2_CID_R_GAIN,
		.name = "R GAIN",
		.type = V4L2_CTRL_TYPE_INTEGER,
		.min = 32,
		.max = 1024,
		.step = 1,
		.def = 256,
		.flags = V4L2_CTRL_FLAG_VOLATILE,
	},
	{
		.ops = &vfe_ctrl_ops,
		.id = V4L2_CID_G_GAIN,
		.name = "G GAIN",
		.type = V4L2_CTRL_TYPE_INTEGER,
		.min = 32,
		.max = 1024,
		.step = 1,
		.def = 256,
		.flags = V4L2_CTRL_FLAG_VOLATILE,
	},
	{
		.ops = &vfe_ctrl_ops,
		.id = V4L2_CID_B_GAIN,
		.name = "B GAIN",
		.type = V4L2_CTRL_TYPE_INTEGER,
		.min = 32,
		.max = 1024,
		.step = 1,
		.def = 256,
		.flags = V4L2_CTRL_FLAG_VOLATILE,
	},
	{
		.ops = &vfe_ctrl_ops,
		.id = V4L2_CID_AUTO_FOCUS_INIT,
		.name = "AutoFocus Initial",
		.type = V4L2_CTRL_TYPE_BUTTON,
		.min = 0,
		.max = 0,
		.step = 0,
		.def = 0,
	},
	{
		.ops = &vfe_ctrl_ops,
		.id = V4L2_CID_AUTO_FOCUS_RELEASE,
		.name = "AutoFocus Release",
		.type = V4L2_CTRL_TYPE_BUTTON,
		.min = 0,
		.max = 0,
		.step = 0,
		.def = 0,
	},
	{
		.ops = &vfe_ctrl_ops,
		.id = V4L2_CID_GSENSOR_ROTATION,
		.name = "Gsensor Rotaion",
		.type = V4L2_CTRL_TYPE_INTEGER,
		.min = -180,
		.max = 180,
		.step = 90,
		.def = 0,
	},
	{
		.ops = &vfe_ctrl_ops,
		.id = V4L2_CID_TAKE_PICTURE,
		.name = "Take Picture",
		.type = V4L2_CTRL_TYPE_INTEGER,
		.min = 0,
		.max = 16,
		.step = 1,
		.def = 0,
	},
	{
		.ops = &vfe_ctrl_ops,
		.id = V4L2_CID_SENSOR_TYPE,
		.name = "Sensor type",
		.type = V4L2_CTRL_TYPE_MENU,
		.min = 0,
		.max = 1,
		.def = 0,
		.menu_skip_mask = 0x0,
		.qmenu = sensor_info_type,
		.flags = V4L2_CTRL_FLAG_VOLATILE,
	},
};
static const s64 iso_qmenu[] = {
	50, 100, 200, 400, 800,
};
static const s64 exp_bias_qmenu[] = {
	-4, -3, -2, -1, 0, 1, 2, 3, 4,
};

static int vfe_init_controls(struct v4l2_ctrl_handler *hdl)
{
	struct v4l2_ctrl *ctrl;
	unsigned int i, ret = 0;

	v4l2_ctrl_handler_init(hdl, 39 + ARRAY_SIZE(custom_ctrls));
	v4l2_ctrl_new_std(hdl, &vfe_ctrl_ops, V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
	v4l2_ctrl_new_std(hdl, &vfe_ctrl_ops, V4L2_CID_CONTRAST, 0, 128, 1, 0);
	v4l2_ctrl_new_std(hdl, &vfe_ctrl_ops, V4L2_CID_SATURATION, -4, 4, 1, 0);
	v4l2_ctrl_new_std(hdl, &vfe_ctrl_ops, V4L2_CID_HUE, -180, 180, 1, 0);
	v4l2_ctrl_new_std(hdl, &vfe_ctrl_ops, V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
	ctrl = v4l2_ctrl_new_std(hdl, &vfe_ctrl_ops, V4L2_CID_EXPOSURE, 0, 65536*16, 1, 0);
	if (ctrl != NULL)
		ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
	v4l2_ctrl_new_std(hdl, &vfe_ctrl_ops, V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
	ctrl = v4l2_ctrl_new_std(hdl, &vfe_ctrl_ops, V4L2_CID_GAIN, 1*16, 64*16-1, 1, 1*16);
	if (ctrl != NULL)
		ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
	v4l2_ctrl_new_std_menu(hdl, &vfe_ctrl_ops, V4L2_CID_POWER_LINE_FREQUENCY,
		V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0, V4L2_CID_POWER_LINE_FREQUENCY_AUTO);
	v4l2_ctrl_new_std(hdl, &vfe_ctrl_ops, V4L2_CID_HUE_AUTO, 0, 1, 1, 1);
	v4l2_ctrl_new_std(hdl, &vfe_ctrl_ops, V4L2_CID_WHITE_BALANCE_TEMPERATURE, 2800, 10000, 1, 6500);
	v4l2_ctrl_new_std(hdl, &vfe_ctrl_ops, V4L2_CID_SHARPNESS, -32, 32, 1, 0);
	v4l2_ctrl_new_std(hdl, &vfe_ctrl_ops, V4L2_CID_CHROMA_AGC, 0, 1, 1, 1);
	v4l2_ctrl_new_std_menu(hdl, &vfe_ctrl_ops, V4L2_CID_COLORFX,
		V4L2_COLORFX_SET_CBCR, 0, V4L2_COLORFX_NONE);
	v4l2_ctrl_new_std(hdl, &vfe_ctrl_ops, V4L2_CID_AUTOBRIGHTNESS, 0, 1, 1, 1);
	v4l2_ctrl_new_std(hdl, &vfe_ctrl_ops, V4L2_CID_BAND_STOP_FILTER, 0, 1, 1, 1);
	v4l2_ctrl_new_std(hdl, &vfe_ctrl_ops, V4L2_CID_ILLUMINATORS_1, 0, 1, 1, 0);
	v4l2_ctrl_new_std(hdl, &vfe_ctrl_ops, V4L2_CID_ILLUMINATORS_2, 0, 1, 1, 0);
	v4l2_ctrl_new_std_menu(hdl, &vfe_ctrl_ops, V4L2_CID_EXPOSURE_AUTO,
		V4L2_EXPOSURE_APERTURE_PRIORITY, 0, V4L2_EXPOSURE_AUTO);
	v4l2_ctrl_new_std(hdl, &vfe_ctrl_ops, V4L2_CID_EXPOSURE_ABSOLUTE, 1, 1000000, 1, 1);
	v4l2_ctrl_new_std(hdl, &vfe_ctrl_ops, V4L2_CID_EXPOSURE_AUTO_PRIORITY, 0, 1, 1, 0);
	v4l2_ctrl_new_std(hdl, &vfe_ctrl_ops, V4L2_CID_FOCUS_ABSOLUTE, 0, 127, 1, 0);
	v4l2_ctrl_new_std(hdl, &vfe_ctrl_ops, V4L2_CID_FOCUS_RELATIVE, -127, 127, 1, 0);
	v4l2_ctrl_new_std(hdl, &vfe_ctrl_ops, V4L2_CID_FOCUS_AUTO, 0, 1, 1, 1);
	v4l2_ctrl_new_int_menu(hdl, &vfe_ctrl_ops, V4L2_CID_AUTO_EXPOSURE_BIAS, ARRAY_SIZE(exp_bias_qmenu) - 1,
		ARRAY_SIZE(exp_bias_qmenu)/2, exp_bias_qmenu);
	v4l2_ctrl_new_std_menu(hdl, &vfe_ctrl_ops, V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE,
		V4L2_WHITE_BALANCE_SHADE, 0, V4L2_WHITE_BALANCE_AUTO);
	v4l2_ctrl_new_std(hdl, &vfe_ctrl_ops, V4L2_CID_WIDE_DYNAMIC_RANGE, 0, 1, 1, 0);
	v4l2_ctrl_new_std(hdl, &vfe_ctrl_ops, V4L2_CID_IMAGE_STABILIZATION, 0, 1, 1, 0);
	v4l2_ctrl_new_int_menu(hdl, &vfe_ctrl_ops, V4L2_CID_ISO_SENSITIVITY, ARRAY_SIZE(iso_qmenu) - 1,
		ARRAY_SIZE(iso_qmenu)/2 - 1, iso_qmenu);
	v4l2_ctrl_new_std_menu(hdl, &vfe_ctrl_ops, V4L2_CID_ISO_SENSITIVITY_AUTO,
		V4L2_ISO_SENSITIVITY_AUTO, 0, V4L2_ISO_SENSITIVITY_AUTO);
	v4l2_ctrl_new_std_menu(hdl, &vfe_ctrl_ops, V4L2_CID_SCENE_MODE,
		V4L2_SCENE_MODE_TEXT, 0, V4L2_SCENE_MODE_NONE);
	ctrl = v4l2_ctrl_new_std(hdl, &vfe_ctrl_ops, V4L2_CID_3A_LOCK, 0, 7, 0, 0);
	if (ctrl != NULL)
		ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
	v4l2_ctrl_new_std(hdl, &vfe_ctrl_ops, V4L2_CID_AUTO_FOCUS_START, 0, 0, 0, 0);
	v4l2_ctrl_new_std(hdl, &vfe_ctrl_ops, V4L2_CID_AUTO_FOCUS_STOP, 0, 0, 0, 0);
	ctrl = v4l2_ctrl_new_std(hdl, &vfe_ctrl_ops, V4L2_CID_AUTO_FOCUS_STATUS, 0, 7, 0, 0);
	if (ctrl != NULL)
		ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
	v4l2_ctrl_new_std_menu(hdl, &vfe_ctrl_ops, V4L2_CID_AUTO_FOCUS_RANGE,
		V4L2_AUTO_FOCUS_RANGE_INFINITY, 0, V4L2_AUTO_FOCUS_RANGE_AUTO);
	v4l2_ctrl_new_std_menu(hdl, &vfe_ctrl_ops, V4L2_CID_FLASH_LED_MODE,
		V4L2_FLASH_LED_MODE_RED_EYE, 0, V4L2_FLASH_LED_MODE_NONE);
	v4l2_ctrl_new_std(hdl, &vfe_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
	v4l2_ctrl_new_std(hdl, &vfe_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0);

	for (i = 0; i < ARRAY_SIZE(custom_ctrls); i++)
		v4l2_ctrl_new_custom(hdl, &custom_ctrls[i], NULL);

	if (hdl->error) {
		ret = hdl->error;
		v4l2_ctrl_handler_free(hdl);
	}

	return ret;
}

static void probe_work_handle(struct work_struct *work)
{
	struct vfe_dev *dev = container_of(work, struct vfe_dev, probe_work.work);
	int ret = 0, i, video_cnt = 1, video_num;
	int input_num;
	int device_valid_count = 0;
	struct video_device *vfd;
	struct vb2_queue *q;

	mutex_lock(&probe_hdl_lock);
	vfe_print("probe_work_handle start!\n");
	vfe_dbg(0, "v4l2_device_register\n");
	/* v4l2 device register */
	ret = v4l2_device_register(&dev->pdev->dev, &dev->v4l2_dev);
	if (ret) {
		vfe_err("Error registering v4l2 device\n");
		goto probe_hdl_end;
	}

	ret = vfe_init_controls(&dev->ctrl_handler);
	if (ret) {
		vfe_err("Error v4l2 ctrls new!!\n");
		goto probe_hdl_unreg_dev;
	}
	dev->v4l2_dev.ctrl_handler = &dev->ctrl_handler;

	dev_set_drvdata(&dev->pdev->dev, (dev));
	vfe_dbg(0, "v4l2 subdev register\n");
	/* v4l2 subdev register */
	/*Register ISP subdev*/
	sunxi_isp_get_subdev(&dev->isp_sd, dev->isp_sel);
	sunxi_isp_register_subdev(&dev->v4l2_dev, dev->isp_sd);
	/*Register CSI subdev*/
	sunxi_csi_get_subdev(&dev->csi_sd, dev->csi_sel);
	sunxi_csi_register_subdev(&dev->v4l2_dev, dev->csi_sd);
	/*Register MIPI subdev*/
	sunxi_mipi_get_subdev(&dev->mipi_sd, dev->mipi_sel);
	sunxi_mipi_register_subdev(&dev->v4l2_dev, dev->mipi_sd);
	/*Register flash subdev*/
	if (dev->ccm_cfg[0]->flash_used || dev->ccm_cfg[1]->flash_used) {
		sunxi_flash_get_subdev(&dev->flash_sd, dev->flash_sel);
		sunxi_flash_register_subdev(&dev->v4l2_dev, dev->flash_sd);
	}
	/*Register Sensor subdev*/
	dev->is_same_module = 0;
#ifdef CONFIG_PM_RUNTIME
	pm_runtime_enable(&dev->pdev->dev);
#endif
	vfe_resume_trip(dev);
	for (input_num = 0; input_num < dev->dev_qty; input_num++) {
		vfe_print("v4l2 subdev register input_num = %d\n", input_num);
		if (!strcmp(dev->ccm_cfg[input_num]->ccm, "")) {
			vfe_err("Sensor name is NULL!\n");
			goto snesor_register_end;
		}
		if (dev->is_same_module) {
			dev->ccm_cfg[input_num]->sd = dev->ccm_cfg[input_num-1]->sd;
			vfe_dbg(0, "num = %d , sd_0 = %p, sd_1 = %p\n", input_num,
					dev->ccm_cfg[input_num]->sd, dev->ccm_cfg[input_num-1]->sd);
			goto snesor_register_end;
		}

		if ((dev->dev_qty > 1) && (input_num+1 < dev->dev_qty)) {
			if ((!strcmp(dev->ccm_cfg[input_num]->ccm, dev->ccm_cfg[input_num+1]->ccm)))
				dev->is_same_module = 1;
		}
		if (dev->vip_define_sensor_list == 1) {
			if (dev->ccm_cfg[input_num]->sensor_cfg_ini->power_settings_enable == 1)
				cpy_ccm_power_settings(dev->ccm_cfg[input_num]);
		}
#ifdef _REGULATOR_CHANGE_
#else
		if (vfe_device_regulator_get(&dev->pdev->dev, dev->ccm_cfg[input_num], input_num)) {
			vfe_err("vfe_device_regulator_get error at input_num = %d\n", input_num);
			goto snesor_register_end;
		}
#endif
		vfe_print("vfe sensor detect start! input_num = %d\n", input_num);
		dev->input = input_num;
		if (vfe_sensor_register_check(dev, &dev->v4l2_dev, dev->ccm_cfg[input_num],
					&dev->dev_sensor[input_num], input_num) == NULL) {
			vfe_err("vfe sensor register check error at input_num = %d\n", input_num);
			dev->device_valid_flag[input_num] = 0;
			/* goto snesor_register_end; */
		} else {
			dev->device_valid_flag[input_num] = 1;
			device_valid_count++;
		}
		if (dev->ccm_cfg[input_num]->is_isp_used && dev->ccm_cfg[input_num]->is_bayer_raw) {
			if (read_ini_info(dev, input_num, "/system/etc/hawkview/"))
				vfe_warn("read ini info fail\n");
		}

		if (dev->ccm_cfg[input_num]->act_used == 1) {
			dev->dev_act[input_num].addr = (unsigned short)(dev->ccm_cfg[input_num]->act_slave>>1);
			strcpy(dev->dev_act[input_num].type, dev->ccm_cfg[input_num]->act_name);
			vfe_actuator_subdev_register(dev, dev->ccm_cfg[input_num], &dev->dev_act[input_num]);
		}
snesor_register_end:
		vfe_dbg(0, "dev->ccm_cfg[%d] = %p\n", input_num, dev->ccm_cfg[input_num]);
		vfe_dbg(0, "dev->ccm_cfg[%d]->sd = %p\n", input_num, dev->ccm_cfg[input_num]->sd);
		vfe_dbg(0, "dev->ccm_cfg[%d]->power.iovdd = %p\n", input_num, dev->ccm_cfg[input_num]->power.iovdd);
		vfe_dbg(0, "dev->ccm_cfg[%d]->power.avdd = %p\n", input_num, dev->ccm_cfg[input_num]->power.avdd);
		vfe_dbg(0, "dev->ccm_cfg[%d]->power.dvdd = %p\n", input_num, dev->ccm_cfg[input_num]->power.dvdd);
		vfe_dbg(0, "dev->ccm_cfg[%d]->power.afvdd = %p\n", input_num, dev->ccm_cfg[input_num]->power.afvdd);
	}
	dev->input = -1;
	/*video device register */
#if defined(CH_OUTPUT_IN_DIFFERENT_VIDEO)
	if (dev->id == 0)
		video_cnt = MAX_CH_NUM;
	else
		video_cnt = 1;
#else
	video_cnt = 1;
#endif
	for (i = 0; i < video_cnt; i++) {
		vfd = video_device_alloc();
		if (!vfd) {
			vfe_err("Error video_device_alloc!!\n");
			goto close_clk_pin_power;
		}
		*vfd = vfe_template[dev->id];
		vfd->v4l2_dev = &dev->v4l2_dev;
		if (device_valid_count != 0) {
#if defined(CH_OUTPUT_IN_DIFFERENT_VIDEO)
			if (dev->id == 0)
				video_num = i + VID_N_OFF;
			else
				video_num = dev->id;
#else
			video_num = dev->id;
#endif
			vfd->device_caps = V4L2_CAP_VIDEO_CAPTURE |
									V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
			ret = video_register_device(vfd, VFL_TYPE_VIDEO, video_num);
			if (ret < 0) {
				vfe_err("Error video_register_device!!\n");
				goto probe_hdl_rel_vdev;
			}
		}

		vfd->lock = &dev->buf_lock;
		video_set_drvdata(vfd, dev);

		dev->vfd[i] = vfd;
		vfe_print("V4L2 device registered as %s\n", video_device_node_name(vfd));

		/* Initialize videobuf2 queue as per the buffer type */
		dev->allocate_dev[i] = &dev->pdev->dev;
		vb2_dma_contig_set_max_seg_size(&dev->pdev->dev, 0);
		if (IS_ERR(dev->allocate_dev[i])) {
			vfe_err("Failed to get the context\n");
			goto probe_hdl_rel_vdev;
		}
		/* initialize queue */
		q = &dev->vb_vidq[i];
		q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
		q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
		q->drv_priv = dev;
		q->buf_struct_size = sizeof(struct vfe_buffer);
		q->ops = &vfe_video_qops;
		q->mem_ops = &vb2_dma_contig_memops;
		q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
		q->lock = &dev->buf_lock;

		ret = vb2_queue_init(q);
		if (ret) {
			vfe_err("vb2_queue_init() failed\n");
			vb2_dma_contig_clear_max_seg_size(dev->allocate_dev[i]);
			goto probe_hdl_rel_vdev;
		}

		INIT_LIST_HEAD(&dev->vidq[i].active);
	}

	/* Now that everything is fine, let's add it to device list */
	list_add_tail(&dev->devlist, &devlist);

	ret = sysfs_create_group(&dev->pdev->dev.kobj, &vfe_attribute_group);
	vfe_suspend_trip(dev);
	vfe_print("probe_work_handle end!\n");
	mutex_unlock(&probe_hdl_lock);
	return;
probe_hdl_rel_vdev:
	video_device_release(vfd);
	vfe_print("video_device_release @ probe_hdl!\n");
close_clk_pin_power:
	vfe_suspend_trip(dev);
probe_hdl_unreg_dev:
	vfe_print("v4l2_device_unregister @ probe_hdl!\n");
	v4l2_device_unregister(&dev->v4l2_dev);
probe_hdl_end:
	vfe_err("Failed to install at probe handle\n");
	mutex_unlock(&probe_hdl_lock);
	return;
}

static int vfe_probe(struct platform_device *pdev)
{
	struct device_node *np = pdev->dev.of_node;
	struct vfe_dev *dev;
	int ret = 0;
	int input_num;
	unsigned int i;

	vfe_dbg(0, "vfe_probe\n");

	/*request mem for dev*/
	dev = kzalloc(sizeof(struct vfe_dev), GFP_KERNEL);
	if (!dev) {
		vfe_err("request dev mem failed!\n");
		ret = -ENOMEM;
		goto ekzalloc;
	}
	for (i = 0; i < MAX_INPUT_NUM; i++) {
		dev->isp_gen_set[i] = kzalloc(sizeof(struct isp_gen_settings), GFP_KERNEL);
		if (!dev->isp_gen_set[i]) {
			vfe_err("request isp_gen_settings mem failed!\n");
			return -ENOMEM;
		}
	}

	pdev->id = of_alias_get_id(np, "vfe");
	if (pdev->id < 0) {
		vfe_err("VFE failed to get alias id\n");
		ret = -EINVAL;
		goto freedev;
	}

	of_property_read_u32(np, "cci_sel", &dev->cci_sel);
	of_property_read_u32(np, "csi_sel", &dev->csi_sel);
	of_property_read_u32(np, "mipi_sel", &dev->mipi_sel);
	of_property_read_u32(np, "isp_sel", &dev->isp_sel);

	dev->platform_id = SUNXI_PLATFORM_ID;

	dev->id = pdev->id;
	dev->pdev = pdev;
	dev->generating = 0;
	dev->opened = 0;
	dev->vfe_sensor_power_cnt = 0;
	dev->vfe_s_input_flag = 0;

	vfe_print("pdev->id = %d\n", pdev->id);
	vfe_print("dev->cci_sel = %d\n", dev->cci_sel);
	vfe_print("dev->csi_sel = %d\n", dev->csi_sel);
	vfe_print("dev->mipi_sel = %d\n", dev->mipi_sel);
	vfe_print("dev->isp_sel = %d\n", dev->isp_sel);

	vfe_dev_gbl[dev->id] = dev;

	spin_lock_init(&dev->slock);
	vfe_dbg(0, "fetch sys_config\n");
	/* fetch sys_config! */
	for (input_num = 0; input_num < MAX_INPUT_NUM; input_num++) {
		dev->ccm_cfg[input_num] = &dev->ccm_cfg_content[input_num];
		vfe_dbg(0, "dev->ccm_cfg[%d] = %p\n", input_num, dev->ccm_cfg[input_num]);
		dev->ccm_cfg[input_num]->i2c_addr = i2c_addr;
		strcpy(dev->ccm_cfg[input_num]->ccm, ccm);
		strcpy(dev->ccm_cfg[input_num]->isp_cfg_name, ccm);
		dev->ccm_cfg[input_num]->act_slave = act_slave;
		strcpy(dev->ccm_cfg[input_num]->act_name, act_name);
		dev->vip_define_sensor_list = define_sensor_list;
	}

	ret = fetch_config(dev);
	if (ret) {
		vfe_err("Error at fetch_config\n");
		goto freedev;
	}

	if (vips != 0xffff) {
		pr_info("vips input 0x%x\n", vips);
		dev->ccm_cfg[0]->is_isp_used = (vips&0xf0)>>4;
		dev->ccm_cfg[0]->is_bayer_raw = (vips&0xf00)>>8;
		if ((vips&0xff0) == 0)
			dev->ccm_cfg[0]->act_used = 0;
	}
	vfe_get_regulator(dev);
	ret = vfe_resource_request(pdev, dev);
	if (ret < 0)
		goto freedev;
	/*initial parameter */
	dev->cur_ch = 0;
	dev->isp_init_para.isp_src_ch_mode = ISP_SINGLE_CH;
	for (i = 0; i < MAX_ISP_SRC_CH_NUM; i++)
		dev->isp_init_para.isp_src_ch_en[i] = 0;

	dev->isp_init_para.isp_src_ch_en[dev->id] = 1;

	INIT_DELAYED_WORK(&dev->probe_work, probe_work_handle);
	mutex_init(&dev->stream_lock);
	mutex_init(&dev->opened_lock);
	mutex_init(&dev->buf_lock);
	schedule_delayed_work(&dev->probe_work, msecs_to_jiffies(1));
	/* initial state */
	dev->capture_mode = V4L2_MODE_PREVIEW;
	return 0;
freedev:
	kfree(dev);
ekzalloc:
	vfe_print("vfe probe err!\n");
	return ret;
}

static int vfe_release(void)
{
	struct vfe_dev *dev;
	struct list_head *list;

	vfe_dbg(0, "vfe_release\n");
	while (!list_empty(&devlist)) {
		list = devlist.next;
		list_del(list);
		dev = list_entry(list, struct vfe_dev, devlist);
		kfree(dev);
	}
	vfe_print("vfe_release ok!\n");

	return 0;
}

static int vfe_remove(struct platform_device *pdev)
{
	struct vfe_dev *dev = (struct vfe_dev *)dev_get_drvdata(&pdev->dev);
	int input_num, i, video_cnt = 1;

	/*Unegister ISP subdev*/
	sunxi_isp_unregister_subdev(dev->isp_sd);
	sunxi_isp_put_subdev(&dev->isp_sd, dev->isp_sel);
	/*Unegister CSI subdev*/
	sunxi_csi_unregister_subdev(dev->csi_sd);
	sunxi_csi_put_subdev(&dev->csi_sd, dev->csi_sel);
	/*Unegister MIPI subdev*/
	sunxi_mipi_unregister_subdev(dev->mipi_sd);
	sunxi_mipi_put_subdev(&dev->mipi_sd, dev->mipi_sel);
	/*Unegister flash subdev*/
	if (dev->flash_used == 1) {
		sunxi_flash_unregister_subdev(dev->flash_sd);
		sunxi_flash_put_subdev(&dev->flash_sd, dev->flash_sel);
	}
	mutex_destroy(&dev->stream_lock);
	mutex_destroy(&dev->opened_lock);
	mutex_destroy(&dev->buf_lock);
	sysfs_remove_group(&dev->pdev->dev.kobj, &vfe_attribute_group);
#ifdef USE_SPECIFIC_CCI
	csi_cci_bus_unmatch_helper(dev->cci_sel);
#endif
	vfe_put_regulator(dev);
#ifdef CONFIG_PM_RUNTIME
	pm_runtime_disable(&dev->pdev->dev);
#endif
	for (input_num = 0; input_num < dev->dev_qty; input_num++) {
#ifdef _REGULATOR_CHANGE_
#else
		vfe_device_regulator_put(dev->ccm_cfg[input_num]);
#endif
		if (!dev->ccm_cfg[input_num]->sensor_cfg_ini)
			kfree(dev->ccm_cfg[input_num]->sensor_cfg_ini);
	}
	vfe_resource_release(dev);

#if defined(CH_OUTPUT_IN_DIFFERENT_VIDEO)
	if (dev->id == 0)
		video_cnt = MAX_CH_NUM;
	else
		video_cnt = 1;
#else
	video_cnt = 1;
#endif
	for (i = 0; i < video_cnt; i++) {
		v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
					video_device_node_name(dev->vfd[i]));
		video_unregister_device(dev->vfd[i]);
		vb2_dma_contig_clear_max_seg_size(dev->allocate_dev[i]);
	}

	v4l2_device_unregister(&dev->v4l2_dev);
	v4l2_ctrl_handler_free(&dev->ctrl_handler);
	for (i = 0; i < MAX_INPUT_NUM; i++)
		kfree(dev->isp_gen_set[i]);

	vfe_print("vfe_remove ok!\n");

	return 0;
}

static void vfe_suspend_helper(struct vfe_dev *dev)
{
	if (vfe_i2c_dbg) {
		vfe_print("vfe_i2c_dbg: pin power and clk will not close!!\n");
		return;
	}
	vfe_clk_close(dev);
	vfe_disable_regulator_all(dev);
	vfe_pin_config(dev, 0);
	vfe_gpio_config(dev, 0);
}

static void vfe_resume_helper(struct vfe_dev *dev)
{
	vfe_pin_config(dev, 1);
	vfe_gpio_config(dev, 1);
	vfe_enable_regulator_all(dev);
	vfe_clk_open(dev);
}

static void vfe_suspend_trip(struct vfe_dev *dev)
{
#ifdef CONFIG_PM_RUNTIME
	pm_runtime_put_sync(&dev->pdev->dev);/* call pm_runtime suspend */
#else
	vfe_suspend_helper(dev);
#endif
}
static void vfe_resume_trip(struct vfe_dev *dev)
{
#ifdef CONFIG_PM_RUNTIME
	pm_runtime_get_sync(&dev->pdev->dev);/* call pm_runtime resume */
#else
	vfe_resume_helper(dev);
#endif
}
#ifdef CONFIG_PM_RUNTIME
static int vfe_runtime_suspend(struct device *d)
{
	struct vfe_dev *dev = (struct vfe_dev *)dev_get_drvdata(d);

	vfe_print("vfe_runtime_suspend\n");
	vfe_suspend_helper(dev);

	return 0;
}
static int vfe_runtime_resume(struct device *d)
{
	struct vfe_dev *dev = (struct vfe_dev *)dev_get_drvdata(d);

	vfe_print("vfe_runtime_resume\n");
	vfe_resume_helper(dev);

	return 0;
}
static int vfe_runtime_idle(struct device *d)
{
	if (d) {
		pm_runtime_mark_last_busy(d);
		pm_request_autosuspend(d);
	} else
		vfe_err("%s, vfe device is null\n", __func__);

	return 0;
}
#endif
static int vfe_suspend(struct device *d)
{
	struct vfe_dev *dev = (struct vfe_dev *)dev_get_drvdata(d);

	vfe_print("vfe suspend\n");
	if (vfe_is_opened(dev)) {
		vfe_err("FIXME: dev %s, err happened when calling %s.", dev_name(&dev->pdev->dev), __func__);
		return -1;
	}

	return 0;
}
static int vfe_resume(struct device *d)
{
	vfe_print("vfe resume\n");

	return 0;
}

static void vfe_shutdown(struct platform_device *pdev)
{
#if defined(CONFIG_PM_RUNTIME) || defined(CONFIG_SUSPEND)
	vfe_print("Defined suspend!\n");
#else
	struct vfe_dev *dev = (struct vfe_dev *)dev_get_drvdata(&pdev->dev);
	unsigned int input_num;
	int ret = 0;
	/* close all the device power */
	for (input_num = 0; input_num < dev->dev_qty; input_num++) {
		/* update target device info and select it */
		update_ccm_info(dev, dev->ccm_cfg[input_num]);
		ret = vfe_set_sensor_power_off(dev);
		if (ret != 0)
			vfe_err("sensor power off error at device number %d when csi close!\n", input_num);
	}
#endif
	vfe_print("Vfe Shutdown!\n");
}

static const struct dev_pm_ops vfe_runtime_pm_ops = {

#ifdef CONFIG_PM_RUNTIME
	.runtime_suspend	= vfe_runtime_suspend,
	.runtime_resume	= vfe_runtime_resume,
	.runtime_idle		= vfe_runtime_idle,
#endif
	.suspend	= vfe_suspend,
	.resume	= vfe_resume,
};

static const struct of_device_id sunxi_vfe_match[] = {
	{ .compatible = "allwinner,sunxi-vfe", },
	{},
};

static struct platform_driver vfe_driver = {
	.probe    = vfe_probe,
	.remove   = vfe_remove,
	.shutdown = vfe_shutdown,
	.driver = {
		.name   = VFE_MODULE_NAME,
		.owner  = THIS_MODULE,
	.of_match_table = sunxi_vfe_match,
	.pm     = &vfe_runtime_pm_ops,
	}
};

static int __init vfe_init(void)
{
	int ret;

	vfe_print("Welcome to Video Front End driver\n");
	mutex_init(&probe_hdl_lock);
	sunxi_csi_platform_register();
	sunxi_isp_platform_register();
	sunxi_mipi_platform_register();
	sunxi_flash_platform_register();
	ret = platform_driver_register(&vfe_driver);
	if (ret) {
		vfe_err("platform driver register failed\n");
		return ret;
	}
	vfe_print("vfe_init end\n");
	return 0;
}

static void __exit vfe_exit(void)
{
	vfe_print("vfe_exit\n");
	platform_driver_unregister(&vfe_driver);
	vfe_print("platform_driver_unregister\n");
	vfe_release();
	mutex_destroy(&probe_hdl_lock);
	sunxi_csi_platform_unregister();
	sunxi_isp_platform_unregister();
	sunxi_mipi_platform_unregister();
	sunxi_flash_platform_unregister();
	vfe_print("vfe_exit end\n");
}

module_init(vfe_init);
module_exit(vfe_exit);

MODULE_AUTHOR("raymonxiu");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("Video front end driver for sunxi");
